mayho33
Goto Top

SCCM-TaskSequence per LogonScript triggern

Hallo @ All

Wieder mal stehe ich leicht vor eine Wand und hoffe auf eure Hilfe.

Aktueller Stand:

Im Unternehmen gibt es einige Core-Applicationen die via SCCM (Application die entsprechenden Device-Collections zugewiesen sind (Deployments)) periodisch aktualisiert werden (Patch-Day). Das passiert ca. 1x die Woche, weil sich die Sourcen ständig ändern. Dazu nutzen wir WoL und verteilen die entsprechenden Applications
Für alle Clients die am Patch-Day nicht erreicht werden konnten, weil sie ausgeschaltet waren oder nicht im Haus, müssen die Apps während des Logon aktualisiert werden.

Das funktioniert. Dauert nur manchmal etwas länger. Ein Snipped des entsprechenden Codes im LogonScript.ps1 (per GPO verteilt) siehe hier::
# ensure PSRemoting is enabled !!
# as Admin Enable-PSRemoting –force
Function Start-WinRM()
{
    $ServiceStatus = Get-Service -Name WinRM
    if($ServiceStatus.Status -eq 'Stopped')  
    {
        Start-Service -Name WinRM -ErrorAction SilentlyContinue
    }
}

Function Get-SCCMApps()
{  
    [CmdletBinding()]  
    Param  
    (   
        [Parameter(Mandatory=$false, ValueFromPipeline=$true, Position=0)][string]$AppNames
    ) 
    Begin{
        Start-WinRM
        if (![string]::IsNullOrEmpty($AppNames))
        {
            $AppList = @()

            if($AppNames)
            {
                if($AppNames -match ',')  
                    {$AppList = [Regex]::Split($AppNames,",")}  
                elseif($AppNames -match ';')  
                    {$AppList = [Regex]::Split($AppNames,";")}  
                else
                    {$AppList = $AppNames}
            }
        }
    } 

    Process{  
        $Application = (Get-CimInstance -ClassName CCM_Application -Namespace "root\ccm\clientSDK" | Where-Object {$_.InstallState -like 'NotInstalled'})  
        $toReturn = @()
        if (![string]::IsNullOrEmpty($AppNames))
        {
            foreach ($app in $Application)
            {
                foreach ($search in $AppList)
                {
                    if([regex]::Match($app.FullName, $search, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase).Success)
                    {
                        $toReturn += $app
                    }
                }
            }
        }
        else
        {
            $toReturn = $Application
        }
        
    }  

    End{
        return $toReturn
    }
}

function Invoke-SCCMAppInstall()
{
    [CmdletBinding()]  
    Param  
    (   
        [Parameter(Mandatory=$false, ValueFromPipeline=$true, Position=0)][string]$AppNames
    ) 
    Begin{
        Start-WinRM
        $Computername = "."  
        $AppList = @()

        if(![string]::IsNullOrEmpty($AppNames))
        {
            if($AppNames -match ',')  
                {$AppList = [Regex]::Split($AppNames,",")}  
            elseif($AppNames -match ';')  
                {$AppList = [Regex]::Split($AppNames,";")}  
            else
                {$AppList = $AppNames}
        }
    }

    Process{
        if($AppList -ne $null -or $AppList.count -lt 1)
        {
            $Application = (Get-SCCMApps -AppNames $AppNames)
        }
        else
        {
            $Application = (Get-CimInstance -ClassName CCM_Application -Namespace "root\ccm\clientSDK" | Where-Object {$_.InstallState -like 'NotInstalled'})  
        }

        if (![string]::IsNullOrEmpty($AppNames))
        {
            foreach ($app in $Application)
            {
                foreach ($search in $AppList)
                {
                    if ([regex]::Match($app.FullName, $search, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase).Success)
                    {
                        
                        $installArguments = @{
                        "EnforcePreference"=[uint32] 0;  
                        "Id"="$($app.id)";  
                        "IsMachineTarget"=$app.IsMachineTarget;  
                        "IsRebootIfNeeded"=$false;  
                        "Priority"="High";  
                        "Revision"="$($app.Revision)"}  

                        Invoke-CimMethod -Namespace "root\ccm\clientSDK" -ClassName CCM_Application -ComputerName $Computername -MethodName "Install" -Arguments $installArguments | Out-Null  
                        WaitForCompletition -Application $app
                    }
                }
            }
        }
        else
        {
            foreach ($app in $Application)
            {
                $installArguments = @{
                "EnforcePreference"=[uint32] 0;  
                "Id"="$($app.id)";  
                "IsMachineTarget"=$app.IsMachineTarget;  
                "IsRebootIfNeeded"=$false;  
                "Priority"="High";  
                "Revision"="$($app.Revision)"}  

                Invoke-CimMethod -Namespace "root\ccm\clientSDK" -ClassName CCM_Application -ComputerName $Computername -MethodName "Install" -Arguments $installArguments | Out-Null  
                WaitForCompletition -Application $app
            }
        }
    }
}


function WaitForCompletition()
{
    [CmdletBinding()]  
    Param  
    ( 
        [Parameter(Mandatory=$True, ValueFromPipeline=$true, Position=0)][Object]$Application=""  
    )

    Process{
        Start-WinRM
        do
        {
            $AppStatus = (Get-CimInstance -ClassName CCM_Application -Namespace "root\ccm\clientSDK" | Where-Object {$_.FullName -like $Application.FullName.ToString()})   
            [System.Threading.Thread]::Sleep(3000)
            if($AppStatus.InstallState -eq 'Installed' -and ($AppStatus.PercentComplete -eq 0 -or $AppStatus.PercentComplete -eq 100) )  
            {
                $exitDo = $True
            }
        }
        until ($exitDo -eq $True)
    }
}

# AppNames mit entsprechendem AppCatalog-Name ersetzen
Invoke-SCCMAppInstall -AppNames "java 8,canon"  

Nun gibt es eine neue Vorgabe, nämlich, dass die Core-Apps in einer TS aktualisiert werden. Das Logon-Script soll nun also die TS triggern.
Und hier stehe ich aktuell auch an.

Ich habe eine entsprechende TS erstellt, frage mich aber wie ich sie im Script triggern kann. Die TS einer Collection zuzuweisen kommt nicht in frage, weil der User sie nicht im Software-Center sehen soll.
Einige Foren beschreiben ein Tool (bsp: Trigger-SCCMTaskSequence.exe <PackageID>) Ich will aber kein Tool verwenden, (bzw. ist untersagt) sondern die TS direkt per WMI triggern.

aktuelle Infrastruktur (rudimentät):
SCCM 1809. Clients: ausschließlich Windows 10 Enterprise x64 1809.

Hat jemand eine Idee wie ich das bewerkstelligen kann?

Vielen Dank für eure Unterstützung!

Mayho

Content-Key: 441173

Url: https://administrator.de/contentid/441173

Ausgedruckt am: 29.03.2024 um 12:03 Uhr

Mitglied: emeriks
emeriks 16.04.2019 um 16:45:31 Uhr
Goto Top
Frage am Rande:
Warum Logon- und nicht Startup-Script? Wäre das nicht sinnvoller?
Mitglied: mayho33
mayho33 16.04.2019 um 16:59:13 Uhr
Goto Top
Wenn es nach mir ginge würde ich sogar nur Delta-Copy (Robocopy via "HKLM\...\Run") machen. Leider habe ich Vorgaben und die besagt TS + LogonScript.

Es gibt bestimmt 100te bessere Möglichkeiten, aber wenn du eine Domain-Architect vor der Nase sitzen hast, kann du 1000 mal bessere Vorschläge liefern. Der DomAr...ch hat das letzte Wort.
Mitglied: Th0mKa
Lösung Th0mKa 17.04.2019 um 06:22:32 Uhr
Goto Top
Zitat von @mayho33:

Es gibt bestimmt 100te bessere Möglichkeiten, aber wenn du eine Domain-Architect vor der Nase sitzen hast, kann du 1000 mal bessere Vorschläge liefern. Der DomAr...ch hat das letzte Wort.

Moin,

in größeren Umgebungen ist ein Standard halt wertvoll, wenn auch nicht immer ideal. Einen Lösungsansatz könntest du hier finden.

/Thomas]
Mitglied: mayho33
mayho33 17.04.2019 aktualisiert um 16:43:51 Uhr
Goto Top
Danke für dem Link @Th0mKa !

Den kannte ich sogar schon. Dein Hinweis hat dann aber endlich gezündet!!

Ich war nur zu doof genauer zu lesen, weil ich nun schon die 100ste Variante ausprobiert habe und nebenbei noch an was anderem schnitze... Da ist mir wohl was durcheinander gekommen

Habe immer
 Invoke-CimMethod -Namespace "root\ccm\clientSDK" -ClassName CCM_ProgramsManager -ComputerName $env:COMPUTERNAME -MethodName "ExecutePrograms" -Arguments $installArguments | Out-Null   


verwendet anstatt
 Invoke-WmiMethod -Namespace "root\ccm\clientSDK" -Class "CCM_ProgramsManager" -Name "ExecutePrograms" -ArgumentList $installArguments  # -Name "ExecutePrograms" -Arguments $installArguments   

@mayho33 <<= Leicht betriebsblind


Jetzt passt's perfekt!

$targetServer = "server.test.local"  

$targetPackageID =@{
"test.local"="PAC0005A"  
"prod.local"="PAC00174";  
"schul.local"=" PAC0020B";  
}

function WaitForCompletition()
{
    [CmdletBinding()]  
    Param  
    ( 
        [Parameter(Mandatory=$True, ValueFromPipeline=$true, Position=0)][string]$PackageID
    )

    Process{
        
        do
        {
            $AppStatus = (Get-WmiObject -Class CCM_Program -Namespace "root\ccm\clientsdk" | Where-Object {$_.PackageID -eq $PackageID})  
            
            [System.Threading.Thread]::Sleep(3000)
            if($AppStatus.EvaluationState -eq 17)
            {
                $exitDo = $True
            }
        }
        until ( ($exitDo -eq $True))
    }
}

$installArguments = Get-WmiObject -Class "CCM_Program" -ComputerName $env:COMPUTERNAME -Namespace "ROOT\ccm\ClientSDK" | Where { $_.PackageId -eq $targetPackageID[$env:UserDnsDomain] }  

Invoke-WmiMethod -Namespace "root\ccm\clientSDK" -Class "CCM_ProgramsManager" -Name "ExecutePrograms" -ArgumentList $installArguments  # -Name "ExecutePrograms" -Arguments $installArguments  
WaitForCompletition -PackageID $targetPackageID[$env:UserDnsDomain]