question

TBingeman avatar image
0 Votes"
TBingeman asked StefanHorz published

Summary emails

I have a runbook that is going to multiple servers to run a script. I have it set up to use concurrency but I need to make sure that we know the results of the script ran on each server in a single email instead of receiving 1.2k emails when the runbook runs. I have been unable to find a way to do this and was hoping that someone here would be able to help me in getting this completed. I am a novice at creating runbooks and currently have no real training on how to use Orchestrator.

msc-orchestrator
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

StefanHorz avatar image
0 Votes"
StefanHorz answered TBingeman commented

Hi @TBingeman,
one option is to redesign the Runbooks. One with "Monitor Date/Time" and the summary email. And the second one with "Read Line" to get the servers and the Activities which should be triggered for each server.
Find the ois_export with the modifications here: https://1drv.ms/u/s!AkXRVOcQ_Bj_iNoQDAcR3X-Pi4zinQ
Define the line for each result in the properties of the second Runbook and return it with "Return Data":

128043-clearcache-2-doing.jpg

Trigger this Runbook with the first Runbook and use "Flatten with line breaks" in the properties of the "Invoke Runbook" Activity.
127990-clearcache-1-trigger.jpg

Important is to check "Wait for Completion"!
128055-clearcache-1-trigger-waitforcompletion.jpg

In "Send EMail" subscribe the Result from "Invoke Runbook".

Regards,
Stefan



· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @StefanHorz ,

Thank you for what you have sent me. The only issue I have yet is that the DeletedItems variable is not being added to the email. Below is an example of what I am getting and what I should be getting.

What appears in the email:
The server SERVER has had items removed from the CCM cache as they were older than 30 days.

What should appear in the email:
The server SERVER has had 96 items removed from the CCM cache as they were older than 30 days.

Can you tell me what is wrong that I am not getting the expected results in the email?

128030-update-server-healthois-export.txt


0 Votes 0 ·
AndreasBaumgarten avatar image
0 Votes"
AndreasBaumgarten answered TBingeman commented

Hi @TBingeman ,

one option is to write the output of all scripts in one text file (file-name for instance with a timestamp) in one shared folder (if you have more than one Runbook Server). After all scripts are done you have two options:

  • Attach the file to an email

  • Read the file content and put this in the email body


(If the reply was helpful please don't forget to upvote and/or accept as answer, thank you)

Regards
Andreas Baumgarten

· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Can you tell me how to implement your suggestion? I do not know how to do what you are suggesting.

0 Votes 0 ·

Hi @TBingeman ,

how your runbook looks like? How your script looks like?


(If the reply was helpful please don't forget to upvote and/or accept as answer, thank you)

Regards
Andreas Baumgarten

0 Votes 0 ·

Here is an export of my runbook folder. This should give you everything you are looking for. Just rename it to ClearCache.ois-export.

127262-clearcacheois-export.txt


0 Votes 0 ·
AndreasBaumgarten avatar image
0 Votes"
AndreasBaumgarten answered AndreasBaumgarten edited

Hi @TBingeman ,

first question: Why are you using different Runbooks with just a few Activities (2 to 4 activites) in each Runbook? Is there a reason for this?
May approach would be just using one Runbook.

Some thoughts:

  • Create a shared folder for the log files on the Runbook server (if you have more than one Runbook Server)


  • in the Runbook:

  • Create a file in the shared folder with dynamic filename using date/time details (e.g. yyyyMMdd-HHmmss.txt / 20210828-115600-log.txt)

  • Modify your PowerShell scripts to write the required results/output in the created text file (Write-Host doesn't work in a Runbook, you could Write-Output instead)

  • Create an email and attach the text file stored in the shared folder (use the Run behavior "Flattern" in the options of the last .Net Script activity before the Send Mail activity. This should prevent to send more than one email)

The Runbook could look like this (you could create the text file name in the first PowerShell script instead):

127218-image.png


(If the reply was helpful please don't forget to upvote and/or accept as answer, thank you)

Regards
Andreas Baumgarten


image.png (26.2 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

TBingeman avatar image
0 Votes"
TBingeman answered

@AndreasBaumgarten,

The reason for the multiple runbooks in this process is to run the script against 25 machines concurrently instead of one after the other. This is why the email portion needs to be separated out so only 1 email is generated instead of 1 email for each server. This is the first time I am using Orchestrator and need to know how to set this up correctly to do what we need it to do.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

AndreasBaumgarten avatar image
0 Votes"
AndreasBaumgarten answered TBingeman commented

Hi @TBingeman ,

Just to get your requirements:
You want to run the "Get Items" and "Delete Items" scripts in batches of 25 parallel/concurrently?
You want the result of 1.2k script jobs in one email?

If so, using 3 runbooks doesn't work.
The second runbook will be executed for each server in the list (1.2 k servers?) and will trigger the third runbook 1.2k times = 1.2 k emails. That's the way Orchestrator works.

In my opinion the only way it could work is with one runbook and redesigned scripts.

I would merge the "Get Items" script with the "Delete Items" script and inside the PowerShell script using an option to run the PowerShell commands as jobs in parallel.
Maybe this helps: https://devblogs.microsoft.com/powershell/powershell-foreach-object-parallel-feature/
Every output will be written in the same text file -> 1.2k outputs in one text file
Flattern the output of the script activity and send one email with the text file as an attachment after the script activity is done


(If the reply was helpful please don't forget to upvote and/or accept as answer, thank you)

Regards
Andreas Baumgarten



· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @AndreasBaumgarten ,

You are correct about the 2 requirements and I see where what I have set up would create 1.2k emails. I am by no means an expert in PowerShell or in Orchestrator. How would you combine the 2 scripts into a single PowerShell script that would run on 25 servers at a time, in parallel, and only run the delete portion if the get items portion of the script is > 0?

0 Votes 0 ·
AndreasBaumgarten avatar image
0 Votes"
AndreasBaumgarten answered TBingeman commented

Hi @TBingeman ,

this script maybe helps to get an idea how to combine 2 scripts:

 $result2 = "" # Reset $result2 variable
 1..100 | ForEach-Object { # use your server name list here instead of 1..100 / runs 100 times
     # Add your first script here and set $result1 with 1 or 0 
     $result1 = 0, 1 | Get-Random # Just for demo to get a $result1 with value - Get random 0 or 1 and set $result1
     # If $result = 0 -> run the second script
     if ($result1 -eq 0) {
         # Put your second script here
         Write-Output "Loop $_ - Your second script should run because result1 = 0 "
         $result2 += "Something $_`r`n" # Create output of script 2
     } 
 }
 $result2 # Write $result2 in one txt file

Maybe this helps with PowerShell multithreading: https://adamtheautomator.com/powershell-multithreading/


(If the reply was helpful please don't forget to upvote and/or accept as answer, thank you)

Regards
Andreas Baumgarten

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @AndreasBaumgarten ,

So following what you provided, I have the attached127628-clear-sccmcacheps1.txt script. My current issue is that it just runs the script on the local server and not each server in the list. Can you tell me what I am doing wrong? Also in the article you posted, it says to use the -parallel switch but it seems that this switch is not available to us in PowerShell 5.1.


0 Votes 0 ·
AndreasBaumgarten avatar image
0 Votes"
AndreasBaumgarten answered

Hi @TBingeman ,

Running remote commands / PowerShell remoting:
https://docs.microsoft.com/en-us/powershell/scripting/learn/remoting/running-remote-commands?view=powershell-7.1#windows-powershell-remoting

The "Foreach-Object -Parallel" is only available in PowerShell 7. You can try to call PowerShell 7 from a PowerShell 5.
The second link I posted should work with PowerShell 5.

I would recommend to "start simple": Try to get it running with a few servers at the beginning (about 25 or 100 servers). Later increase the number of servers and try to get it running in parallel if required.


(If the reply was helpful please don't forget to upvote and/or accept as answer, thank you)

Regards
Andreas Baumgarten

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

StefanHorz avatar image
0 Votes"
StefanHorz answered TBingeman commented

yes,
because you set $DeltetedItems in an invoked PS-Session you must Return it from this:

 $DeletedItems = Invoke-Command -ComputerName \`d.T.~Ed/{15F3987F-14B1-427B-9F7E-DE7044DE0C49}.LineText\`d.T.~Ed/{
            
         #stop the Windows Update and CCM Services
         Stop-Service -Name wuauserv -Confirm:$false -Force
    
         #Remove-Item -Path C:\Windows\SoftwareDistribution\* -Confirm:$false -Force -Recurse
    
         #discover
         $MinDays = 30
         $UIResourceMgr = New-Object -Com UIResource.UIResourceMgr
         $Cache = $UIResourceMgr.GetCacheInfo()
         $DeletedItems = ($Cache.GetCacheElements() | where-object {[datetime]$_.LastReferenceTime -lt (get-date).adddays(-$mindays)} | Measure-object).Count 
                 if ($DeletedItems -gt 0) {
             $result1 = 0
         }else{
             $result1 = 1
         }
             # If $result = 0 -> run the second script
             if ($result1 -eq 0) {
             #remediate
             $MinDays = 30
             $UIResourceMgr = New-Object -ComObject UIResource.UIResourceMgr
             $Cache = $UIResourceMgr.GetCacheInfo()
             $Cache.GetCacheElements() |
             where-object {[datetime]$_.LastReferenceTime -lt (get-date).adddays(-$mindays)} | 
             foreach {
             #$Cache.DeleteCacheElement($_.CacheElementID)
             }
         Restart-Service -Name CCMExec -Confirm:$false -Force
            
         }
         do {$WinUpdate = get-service wuauserv | select Status -ExpandProperty Status ; Start-Service -Name wuauserv -Confirm:$false | start-sleep 5} while ($WinUpdate -ne "Running")
    
         #do {$CCMExec = get-service CCMExec | select Status -ExpandProperty Status ; Start-Service -Name CCMExec -Confirm:$false | start-sleep 5} while ($CCMExec -ne "Running")
        
     Return $DeletedItems
 }
 $DeletedItems

Regards,
Stefan

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi @StefanHorz ,

I decided not to include the number of items and only state what server had items deleted. The only issue I have left is that the second runbook is still doing each server one after another instead of 25 servers at a time in parallel. How can I make it that the servers are done in blocks of 25?

0 Votes 0 ·
StefanHorz avatar image
0 Votes"
StefanHorz answered StefanHorz published

Hi @TBingeman,

you can set the maximum of concurrent Runbooks to 25 in the properties of the second Runbook:

129116-concurrency-1-setting.jpg

In the "Read Line" Activity you can configure the lines for the blocks like in the screenshot below. The Parameters firstline and lastline are configured in the "Initialize Data" Activity.

129181-concurrency-2-readline.jpg

To get first and lastline for each block use this script in a "Run .Net Script" Activity:

 $Concurrency = 25
 $YOURFILE = "E:\Performance\Clear SCCM Cache\ServerList.txt"
    
 [int]$lines = (Get-Content $YOURFILE | Measure-Object -Line).Lines
 $blocks = [math]::Round($lines / $Concurrency)
    
    
 $firstline = @()
 $lastline = @()
 $i = 1
    
 while(($i -lt $lines) ){
    $firstline += $i
    $i = $i + $blocks
    if ( ($i - 1) -le $lines) {
         $lastline += ($i - 1)
    }
    else {
     $lastline += $lines
    }   
         
 }   


129182-concurrency-3-measuerfile.jpg129172-update-server-health-communityois-export.txt

Regards,
Stefan





5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.