Jak zdalnie wywołać opublikowane zadanie na kliencie SCCM 2012

Witajcie,

W sieci można znaleźć wiele pytań o zdalne wywoływanie akcji klienta SCCM poprzez skrypty.
W oficjalnym SDK do SCCM 2012 nie ma absolutnie nic na temat takiej możliwości. W wersji do SCCM 2007 jest przykład skryptu wykonywanego lokalnie, wywołującego obiekty klas COM CPAppletMgr oraz UIResourceMgr. Niestety, konfiguracja DCOM, która umożliwiałaby zdalne użycie tych obiektów jest conajmniej uciążliwa, a przy okazji bezużyteczna na dłuższą metę, gdyż niedorzecznym była by wiara, że klasy te (a w szczególności GUID’y) nie zmienią się w przyszłości.
Bardziej naturalną formą integracji z SCCM’em jest wykonywanie wywołań WMI.
I tutaj znowu Microsoft podłożył wszystkim autorom skryptów kukułcze jajo – w SDK do wersji 2012 jest jedynie suchy opis klas WMI dostępnych w kliencie i serwerze, jednakże brakuje jakichkolwiek wskazówek dotyczących ich używania.
Po dłuższych poszukiwaniach odnalazłem fantastyczne narzędzie: SMSCLICTR, które zbiera wszystkie możliwe ustawienia i wywołania w proste do użycia biblioteki .NET. Mogą być one wykorzystane także w powershell’u, jednakże często użycie zewnętrznych typów danych w PS jest zabronione przez polityki bezpieczeństwa systemu.
Ostatecznie nie pozostało nic innego, jak utworzenie własnego kawałka kodu, który będzie wykonywał wymagane akcje.

  1. Po pierwsze, konieczne jest wywołanie odświeżenia polityk klienta SCCM. Może to zostać wykonane przez poniższą funkcję:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function ForceMachinePolicyRefresh
    {
    param($clientname, $username, $userpass, $PolicyID)
    $ms = new-object system.management.managementscope
    $ms.Path = "\\$clientname\root\CCM"
    $ms.options.username = $username
    $ms.options.password = $userpass
    $mc = new-object system.management.managementclass($ms, 'SMS_Client', $null)
    $mc.invokeMethod("TriggerSchedule", $PolicyID)
    return $mc
    }

    Parę uwag do powyższego kodu:

    • Połączenie do przestrzeni nazw WMI następuje w formie bezpośredniej, bez użycia rzutowania, dostępnego w powershell na klasę [wmi], z powodu konieczności przekazania poświadczeń. Kod ten może wywoływać WMI zdalnie, dzięki zastosowaniu $ms.options.username które wspierane jest tylko w przypadku zdalnych połączeń.
    • Jest to ogólna funkcja umożliwiająca wymuszenie wywołania dowolnej harmonogramowej akcji. Tak więc może zostać użyta nie tylko do odświeżania polityki komputera, ale także do zastosowania ustawień konfiguracji lokalnej, co zostanie pokazane za moment.
    • Ostatnią rzeczą, dotyczącą tego małego kawałka kodu jest fakt, iż może zostać użyty jako szablon do manipulacji dowolnymi właściwościami i metodami opublikowanymi przez klasę WMI SMS_Client. Dopiero teraz SDK może się okazać pomocne.
  2. Tak więc mając zdefiniowaną tę procedurę pomocniczą możemy przejść do sedna sprawy. Poniższa funkcja służy do uruchomienia wymuszonej publikacji podanego w argumencie pakietu lub aplikacji. Funkcja pobiera wszystkie wymagane argumenty, tak że jest zupełnie niezależna od kontekstu, w którym jest wykonywana:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    function InvokeOptionalAdvertisement
    {
    Param($clientname, $username, $userpass, $advertID, $packID)
    $mc = ForceMachinePolicyRefresh -clientname $clientname -username $username -userpass $userpass -PolicyID "{00000000-0000-0000-0000-000000000021}"
    $ms = new-object system.management.managementscope
    $ms.path = "\\$clientname\root\ccm\policy\Machine\ActualConfig"
    $ms.options.username = $username
    $ms.options.userpass = $userpass
    $query =new-object System.Management.ObjectQuery
    $query.QueryString = "Select * From CCM_SoftwareDistribution where ADV_AdvertisementID = '$advertID' and PKG_PackageID = '$packID'"
    $searcher = new-object system.management.managementobjectsearcher($query)
    $searcher.Scope = $ms
    $advs = $searcher.Get
    $enum = $advs.GetEnumerator()
    $enum.MoveNext()
    $adv = $enum.Current
    $adv.SetPropertyValue("ADV_RepeatRunBehavior", "RerunAlways")
    $adv.SetPropertyValue("ADV_MandatoryAssignments", "True")
    $adv.Put()
    $query1 = new-object System.Management.ObjectQuery
    $query1.QueryString = "Select ScheduledMessageID FROM CCM_Scheduler_ScheduledMessageID like '" + $adv.ADV_AdvertisementID + "-" + $adv.PKG_PackageID + "%'"
    $searcher1 = new-object System.management.managementobjectsearcher($query1)
    $searcher1.scope = $ms
    $scheds = $searcher1.Get()
    $scheds | Foreach-Object { $mc[1].invokeMethod("TriggerSchedule", $_.ScheduledMessageID) }
    return $adv
    }

    No i oczywiście słowo komentarza do powyższego kodu:

    • Na początku wywołujemy odświeżenie polityki komputera, aby mieć pewność, że pracujemy na aktualnych danych publikacji pobranych z SCCMa. Tę akcję wykonujemy przy użyciu naszej pomocniczej procedury.
    • Następnie definiujemy nowy kontekst zarządzania WMI obejmujący aktualnie załadowaną konfigurację klienta SCCM.
    • Kolejno, tworzymy instację klasy ObjectQuery, która reprezentować będzie zapytanie WMI. To zapytanie pobiera z przestrzeni wszystkie obiekty klasy CCM_SoftwareDistributionktóre pasują do przekazanych wymagań.
    • Poprzez wywołanie metody $searcher.Get umieszczamy w zmiennej $advs wszystkie obiekty będące wynikiem zapytania.
    • Dzięki użyciu sztuczki z pobraniem enumeratora i jego właściwości $enum.Current otrzymujemy tylko pojedynczy obiekt, zamiast kolekcji zawierającej ten obiekt.
    • Teraz pora na wykonanie głównego zadania. Modyfikowane są dwie właściwości obranego obiektu, co powoduje, że zamiast opcjonalnej publikacji, na tym konkretnym kliencie staje się ona obowiązkowa i zostanie wykonana przy następnym wywołaniu harmonogramu tej publikacji.
    • Ostatnia część skryptu listuje wszystkie zarejestrowane w systemie obiekty harmonogramu i wymusza ich uruchomienie. To powoduje także wywołanie akcji harmonogramu dla naszej publikacji, którą chcemy wymusić.