Hurtig gennemgang af hvordan jeg har lavet en deployment af Sysinternals Suite klar via Psappdeployment toolkit.

Mål:

Sysinternals suiten installeres i C:\sysinternalssuite
sysmon.exe service installeres
sysinternals mappen tilføjes til %path%

Files and Folders.

Udpak alle filer fra download http://technet.microsoft.com/en-us/sysinternals/bb842062
Hvis man blot nativ vælger at udpakke, vil mappen hedde "sysinternalssuite" mappe navnet bibeholder jeg, sådan det er færrest ændringer.
Fyi. Praktisk vil man i powershell 5 nativ kunne udpakke filerne, sådan dette ikke skal ske før deployment.

File layout:

Powershell appdeployment Toolkit File layout


Placer sysinternalssuite mappen i Psappdeploytment toolkit mappe strukturen, under "Files", disse vil kunne ref via $dfiler variablen.

Herefter skal Deploy-Application.ps1 filen editeres, sådan den klare de 3 ønsker jeg havde til pakken.

Mit powershell script kom til at se sådan ud.

Mit leg tidligere på måneden med psappdeploytoolkit har fået startet et lille projekt, nemlig Poor mans software deployment system, hvilket egentligt er en meget simple executer af software som er wrapped med psappdeploytoolkit.

Version 0.01

Features:

Input en txt file med pc navne som skal have skudt en opdatering ud.
test om maskinen er tændt.
test om en bruger er logget på maskinen og præsentere den på logget bruger unatteded installations UI (psappdeploy)
auto rerun af install script såfremt at en bruger defer installationen ( error 5000 )
psappdeploy installation køre i maskinens system konto.


Prereqs:

Sysinternals suite
GPO, som laver c:\windows\logs\software til en \\computername\logs share  ( test om maskinen er tændt )
GPO, som enabler remote powershell.
GPO, som enabler remote eventlog ( eller port 445 til psexec )

Workflow:

A) Powershell script danner en psexec job file pr maskine som står i input txt filen.
A1) er der bruger på maskinen, skal serviceui benyttes, ellers skal installtion blot køres.
A2)er maskinen offline / ude af huset skal den direkte i rerun køen.
B) Powershell scriptet starter et powershell job pr psexec job file
C) Powershell script adventer alle jobs er færdig og danner nye pc liste såfremt installtionen er defered som køres efter X tid igen som step A)

Eksemple som kan deploy JRE 7u71 f.eks. ( udvikling kode så det er "grimt" )

 

---------------- kode start --------------------------------

Param(
  [string]$filePath
)
$defaltHostlist = "c:\pmsds\pc.txt"
if ($filepath.length -eq "0" )
{
$defaltHostlist = "c:\pmsds\pc.txt"
    Write-Host "Default input file with computernames :" $defaltHostlist
}
else
{
if (test-path $filePath )
{
$defaltHostlist = $filePath
Write-Host "custom input file with computernames : " $defaltHostlist
}
}
# --------------- følgende 3 linjer skal tilpases pr pakke som skal sendes ud
$ApptoInstall = "jre"
$AppDeployVersion = "7u71"
$ToInstall = "
\\pmsds\PMSDS\Software\ToInstall\jre7\Toolkit\Deploy-Application.exe"
# --------------- 
$Sleepsecuntes = "14400"
$pcs = Get-Content $defaltHostlist
"`nLoaded total pc from file $($pcs.count)`n"
$datestamp = Get-DAte  -format "dd-mm-yyyy-HH-mm"
$pmsdsRoot = "c:\pmsds"
$pmsdsJobs = "\jobs"
$pmsdslogs = "\logs"
$slash = "\"
$Filety = ".bat"
$filelog = ".log"
$filererun = ".rerun"
$filebad = ".BAD"
$Jcount = 0
$ServiceUI = "
\\pmsds\PMSDS\Tools\ServiceUIx64.exe "
$cmd = " C:\Windows\System32\cmd.exe /C "
$PSExec = "C:\SysinternalsSuite\psexec.exe \\"
$PSExecSystem = " -s "
$SUI = "_serviceUi"
$loganalyseLine = "C:\Windows\System32\cmd.exe exited on "
$joblog = $pmsdsRoot + $pmsdsJobs + $slash + $jobname
$jobname = $ApptoInstall + $AppDeployVersion
$jobdir = $pmsdsRoot + $pmsdsJobs +$slash +$ApptoInstall + $AppDeployVersion +$slash + $datestamp
$joblogdir = $pmsdsRoot + $pmsdslogs
$joblog = $pmsdsRoot + $pmsdslogs + $slash + $jobname + $filelog
$jobRerun = $jobdir + $slash + $slash + $jobname + $datestamp + $filererun
$jobBAD = $jobdir + $slash  + $slash + $jobname +$datestamp + $filebad

if(!(Test-Path -Path $jobdir)){
    New-Item -ItemType directory -Path $jobdir
}
if(!(Test-Path -Path $joblogdir)){
    New-Item -ItemType directory -Path $joblogdir
}
 foreach($pc in $pcs){
$softwarelogs = '\\'+ $pc + '\logs'
write-host "testing connection to : " $softwarelogs
if (Test-path $softwarelogs )
{
$scriptToRunWithUser =  $PSExec + $pc + $PSExecSystem + $cmd + $ServiceUI + $ToInstall
$scriptToRunNouser = $PSExec + $pc + $PSExecSystem + $cmd + $ToInstall
$runFileuser = $jobdir + $slash  + $pc+  $SUI + $Filety
$runFile = $jobdir + $slash  + $pc + $Filety
#write-host "to write:" $runFile
#write-host "to run: " $scriptToRun
# test om der er en bruger logget ind.
 $SB = {    Get-ChildItem Registry::\HKEY_USERS | Where-Object { Test-Path "$($_.pspath)\Volatile Environment" } | ForEach-Object { (Get-ItemProperty "$($_.pspath)\Volatile Environment").USERNAME }}
    $user = Invoke-Command -ComputerName $pc -ScriptBlock $SB
    write-host "User Loggedon: " $user
    if ($user.length -eq "0")
    {
        $scriptToRunNouser | Out-File $runFile  -Encoding ascii -Force
    }
    else
    {
        $scriptToRunWithUser | Out-File $runFileuser  -Encoding ascii -Force
        }
}
else
{
    $pc.tostring() | Out-File $jobRerun -Append -Encoding ascii
}
}
 get-job  -Name $jobname | remove-job
Foreach ($bat in get-childitem $jobdir){
 
    if ($bat.Extension -eq ".bat")
    {
    write-host "Running at background job : " $bat
    $scriptblock = $cmd + $bat.FullName
    $scriptBlock = [Scriptblock]::Create($scriptblock)
    start-job -Name $jobname -ScriptBlock $scriptblock
    }
}

write-host "All jobs are started sleeping 20 sec"
Start-Sleep -Seconds 20
get-job -Name $jobname | Wait-Job 
get-job -Name $jobname  | Receive-Job -Keep 2>&1 >  $joblog
$loganalyse = Get-Content $joblog
foreach ($line in $loganalyse )
{
    if ($line.ToLower().StartsWith( $loganalyseLine.ToLower()))
        {
         $analyse =  $line.Split(" ")
        $hostname = $analyse.Item(3)
        $psexit = $analyse.Item(7)
            if( $psexit -eq "0.")
             {
             Write-Host "job done"
             Write-Host "hostname: " $analyse.Item(3)
            Write-Host "Exitcode: " $analyse.Item(7)
            }
            elseif ($psexit -eq "5000.")
            {
             write-host "job defered, need to rerun"
            Write-Host "hostname: " $analyse.Item(3)
            Write-Host "Exitcode: " $analyse.Item(7)
            $analyse.Item(3).tostring() | Out-File $jobRerun -Append -Encoding ascii
            }
            else
            {
            write-host "job gone bad, look into it"
            Write-Host "hostname: " $analyse.Item(3)
            Write-Host "Exitcode: " $analyse.Item(7)
            $line.tostring() | Out-File $jobBad -Append -Encoding ascii
       }
    }
   }
   if (Test-Path ($jobRerun))
    {
    Write-Host "waiting this ammount of secondes before rerun: " $Sleepsecuntes
     Start-Sleep -Seconds $Sleepsecuntes
     Invoke-Expression -Command ($PSCommandPath + ' -filePath ' + $jobRerun)
  
   }

---------------- kode slut--------------------------------

De seneste par aftner har jeg leget lidt med PsAppdeploy, dog uden SCCM som det oprindeligt er lavet til.
kort så har jeg "ingen" distributions motor tilrådighed, men jeg kunne godt tænke mig at undersøge hvorlangt jeg kunne komme ved at tænke mig lidt om, og bruge færdige ting fra nettet / indbygget på maskinen.

Psappdeloytoolkit kan hentes på codeplex og er en powershell script/ wrapper som kan brugen omkring installations pakken, under deployment via sccm, dette betyder at det naturligvis også bør kunne tweekes til at køre under andre formål. -> http://psappdeploytoolkit.codeplex.com

En af de ting jeg godt kan lide dem Psappdeloytoolkit er muligheden for interaktion med brugen, f.eks. at fortælle at nu lukke jeg altså din browser ned for at installere en plugin eller applikation osv.

Min tanke er at prøve at deploy nogle task scheduler opgaver som starter installationen, der forhåbentligt kommer til at køre under "system" og ikke en lokalt admin bruger.

Jeg har fundet denne forum indlæg som fortæller med at det bør være muligt http://psappdeploytoolkit.codeplex.com/discussions/538137
det kræver dog at men køre det via en exe file fra MDT, nemlig serviceUI.exe  disse ( 32/64bit) versionerne er placeret i "Tools\arch" mapperne f.eks. \\mdt.install.local\Deploymentshare\Tools\x64

serviceui.exe /?

 Usage: serviceui [-nowait] [ [-session:<sessionid>] | [-process:<process.exe>]] program [arg(x)]  

  -nowait   Don't wait for program completion. Exitcode will not be captured.
    -session  Specify session number to launch in.
    -process  Search for process; program willlaunch in same session.
    program   Name of application to execute.  arg(x)    Argument(s) for program.

 Examples:
  serviceui %windir%\notepad.exe
  serviceui -session:1 %windir%\notepad.exe
  serviceui -process:calc.exe %windir%\notepad.exe "\"my file.txt\""
  serviceui -process:calc.exe "%windir%\notepad.exe" "\"my file.txt\""

Jeg har renamed de 2 serviceui til serviceuix64.exe og serviceuix86.exe for at holde styr på disse 2 varianter.

herefter har jeg lavet en bat file med følgende linje, run.bat
C:\Download\PSAppDeployToolkit_v3.1.5\Tools\ServiceUIx64.exe C:\Download\PSAppDeployToolkit_v3.1.5\Emet5\Toolkit\Deploy-Application.EXE
som så køres af Windows task scheduler, og dette forsager at Deploy-Application.EXE får starter powershell sådan at jeg ser det på min alm non admin desktop session.

Til info så lander msi install loggen her pr default: C:\Windows\Logs\Software

det jeg mangler nu er:
At få det til at virke fra en netværks share, eller lave noget logik som kopier source filerne ud på hver enkelt maskine
At lave noget logik, sådan jeg capture om installationen er gået godt, eller om installationen skal re-scheduler, f,eks når folk vælger at installer på en senere tidspunkt.
At finde en måde at deploy scheduler tasken på.

I øverigt en anden måde at starte Deploy-Application.exe på, kunne være via PSEXEC
psexec -s -i %comspec% /C C:\Download\PSAppDeployToolkit_v3.1.5\Emet5\ToolkitDeploy-Application.EXE
Dette forsager også en interaktion med den på logget bruger.