troubleshooting Question

Powershell Script - Increment Counter?

Avatar of Ron Shorts
Ron ShortsFlag for United States of America asked on
PowershellVB ScriptSCCMScripting Languages
12 Comments1 Solution141 ViewsLast Modified:
Hi Experts,

Looking for some expertise with this script.

Here is what the script does:

1) Reads from a text file with computer names and remotely runs a SCCM advertisement.

2) The advertisement opens some processes - which I have in a loop in this script.  

3) When the processes read 0 the loop is completed, then moves to the next command to RESTART the computer.

4) Is there any way to have this run 3 times, and then shutdown on the 3rd time?

$OutArray = @()
workflow foreachrerun {
    param([string[]]$computers)
    foreach –parallel ($computer in $computers) {
       InlineScript {
Function Start-CCMRerunAdvertisement {
    [CmdLetBinding()]Param(
        [Parameter(Mandatory=$true)][string]$computerName,
        [Parameter(Mandatory=$false)][string]$advertisementId = "*",
        [Parameter(Mandatory=$false)][string]$packageId = "*",
        [Parameter(Mandatory=$false)][int]$maxRun = 1
        #[Parameters(Mandatory=$false)][switch]$moreThanPing = $false
    )
    if($advertisementId -eq "*" -and $packageId -eq "*") {
        Write-Error "You must supply either an AdvertisementID or a PackageID"
        return "Missing Parameters"
        break
    }
    $searchString = "$advertisementId-$packageId-*" 
    if(!(Test-Connection -ComputerName $computername -ErrorAction SilentlyContinue)) {
        if($moreThanPing) { 
            if(!(Get-ChildItem "\\$computername\c$" -ErrorAction SilentlyContinue)) {
                Write-Error "System Offline"
                Return "System Offline"
                break
            }
        } else {
            Return "$Computername is Offline"
            break
        }
    }
    Write-Verbose "Getting ID of ScheduleMessage on $computername"
    $schMsgs = Get-WmiObject -ComputerName $computername -Namespace "root\ccm\policy\machine\actualconfig" -Class CCM_Scheduler_ScheduledMessage
    $thisMsg = $schMsgs | ? { $_.ScheduledMessageID -like $searchString } | Sort ActiveTime -Descending | select -First $maxRun
    if(!$thisMsg) {
        Write-Verbose "Cannot Find Advertisement/Package on Target Computer"
        Return "Cannot Find Advertisment"
        break
    }
    $thisMsg | % {
        [xml]$activeMessage = $_.activeMessage
        $amProgramId = $activeMessage.SoftwareDeploymentMessage.ProgramID
        $amAdvId = $activeMessage.SoftwareDeploymentMessage.AdvertisementID
        $amPkgId = $activeMessage.SoftwareDeploymentMessage.PackageID
        $ScheduledMessageId = $_.ScheduledMessageId
        Write-Verbose  "Restarting $amArogramId (ADV=$amAdvId) (PKG=$amPkgId) for Schedule Message $ScheduledMessageId"
        $softwareDist = Get-WmiObject -ComputerName $computername -Namespace "root\ccm\policy\machine\actualconfig" -Class CCM_SoftwareDistribution -Filter "ADV_AdvertisementID = '$amAdvId' and PKG_PackageID = '$amPkgId'"
        $original_Rerun = $softwareDist.ADV_RepeatRunBehavior
        if($original_Rerun -ne "RerunAlways") {
            write-verbose "Changing Rerun Status from $original_Rerun to RerunAlways"
            $softwareDist.ADV_RepeatRunBehavior = "RerunAlways"
            $softwareDist.put() | Out-Null
        }
        Write-Verbose "Triggering Schedule on $computername"
        Invoke-WmiMethod -ComputerName $computername -Namespace "root\ccm" -Class "SMS_CLIENT" -Name TriggerSchedule $ScheduledMessageId | Out-Null
        Write-Verbose "Sleeping for 5 seconds"
        Start-Sleep -Seconds 5
        if($original_Rerun -ne "RerunAlways") {
            Write-Verbose "Changing Rerun Status back to $original_Rerun"
            $softwareDist.ADV_RepeatRunBehavior = "$original_Rerun"
            $softwareDist.put() | Out-Null
        }
        Return "Advert Reran on succesfully on $computername"
    }
}
function Send-EmailOffline {
    Send-MailMessage -From “admin@domain.com" -To "admin1@domain.com" -SMTPServer mail.domain.com -Subject “$($computername) is Offline" -Body "$($ComputerName) is Offline, please power on and re-run script."
}
function Send-EmailKickit {
    Send-MailMessage -From “admin@domain.com" -To "admin1@domain.com" -SMTPServer mail.domain.com -Subject “$($computername) Completed." -Body "$($ComputerName) Completed and is rebooting."
}
function Test-MyConnection {
    param (
        [Parameter(Mandatory=$true)]
        [System.String]
        $ComputerName
    )
    if (Test-Connection $computername -Quiet -Count 2) {
        Write-Output "Ping successful on $($computerName)"      
        Test-Running -ComputerName $ComputerName 
    }
    else {
        Send-EmailOffline -ComputerName $computername   
    }
  }   
function Test-Running {
    param (
        [Parameter(Mandatory=$true)]
        [System.String]$ComputerName
    )
$processList = @'
    "Name",             "Expected",     "Running"
    "cmd",              "1",            "0"
    "TrustedInstaller", "1",            "0"
    "TIWorker",         "1",            "0"
    "OfficeClickToRun", "2",            "0"
'@ | ConvertFrom-Csv | ForEach-Object {$_.Expected = [int]$_.Expected; $_}
    $splat = @{}
    $splat['ComputerName'] = $computerName
    #Write-Output "Monitoring processes on $($computerName)" 
    Do  {
      $processList | ForEach-Object {
          $_.Running = @(Get-Process $_.Name @splat -ErrorAction SilentlyContinue).Count
      }
      ($processList | Format-Table -AutoSize | Out-String).Split("`r`n", [StringSplitOptions]::RemoveEmptyEntries) | Write-Output
      If ($running = @($processList | Where-Object {$_.Running -ge $_.Expected}).Count) {
          Start-Sleep -Seconds 5
      }
      Write-Output "Monitoring processes on $($computerName)" 
    } Until (-not $running)
    Send-EmailKickit -ComputerName $computername 
    $Today = (Get-Date).ToString('MM-dd-yyyy'),
    $ExactTime = Get-Date -Format "MM-dd-yyyy HHmm tt"
    $Logfile = "c:\input\Log.csv"
    $myobj = "" | Select "Computer", "ExactTime"
    $myobj.Computer = $ComputerName
    $myobj.ExactTime = $($(Get-Date).ToString('yyyy-MM-dd::hh:mm:ss'))

    $OutArray += $myobj
    $OutArray | Export-Csv $Logfile -NoTypeInformation -Append 
    Return "Process count finished on $computername"

# force reboot, after all process requirements met
Restart-Computer -Computer $Computername -Force

} 
            Start-CCMRerunAdvertisement –ComputerName $using:Computer -AdvertisementID "TMC73737" 
            Test-MyConnection -ComputerName $using:Computer
        }
    }
}
$ComputerList  = Get-Content "c:\input\computerlist.txt"
foreachrerun -Computers $ComputerList
ASKER CERTIFIED SOLUTION
Darrell Porter
Enterprise Business Process Architect

Our community of experts have been thoroughly vetted for their expertise and industry experience.

Join our community to see this answer!
Unlock 1 Answer and 12 Comments.
Start Free Trial
Learn from the best

Network and collaborate with thousands of CTOs, CISOs, and IT Pros rooting for you and your success.

Andrew Hancock - VMware vExpert
See if this solution works for you by signing up for a 7 day free trial.
Unlock 1 Answer and 12 Comments.
Try for 7 days

”The time we save is the biggest benefit of E-E to our team. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange.

-Mike Kapnisakis, Warner Bros