02 August 2016

PowerShell: SCCM Client Installer

It was time to upgrade the old SCCM Client Installer. I wanted to add new features and also make the script be able to execute by using parameters. With the help of Sapien's PowerShell Studio, this was very easy to do! I did not include all optional fields, but for my own company, this works great and you can easily modify it if there are additional parameters of the client installer you need in your environment.

The first thing I did was to make the parameters available for the client installer directory, client installer filename, management point, SMS site code, and two switches defining whether to install or uninstall. I centered this script around using the ccmsetup.exe file to both install and uninstall. Another feature I added is the Build parameter. This parameter can be added with the install parameter, or by itself. This configures the SCCM client in preparation for a sysprep of the computer. This is primarily done before sysprepping a machine using SCCM or MDT that captures a reference image. This allows for the client to be already present when the reference image is laid down on a newly imaged computer. It then communicates back to the SCCM server to configure itself as a new client when that reference image is laid down on new machines. I have included command line examples within the script's documentation.

This is a video of the script executing to uninstall the SCCM client on a machine.





This video shows the script installing the SCCM client. You can see that I include the uninstallation of the application first so that if this is being run to fix a machine, it will first uninstall and then install the client. Another thing you will see is that it initializes the installation and then goes on to wait for the installation to complete. I put the waiting in there because once the client begins its install, it closes out the first instance of the ccmsetup.exe and opens up a new one, thereby making the script think the installation finished, when in essence, it did not. I make the script wait because I want to make sure that when the install takes place, it is completely finished when the script closes. When the script executes during a build, especially during a reference image build, it needs to time complete the setup before the sysprep. That is the purpose of the wait. If you do not want it to wait, you can disable lines 264 and 280.


Finally, below is a pic of the script being executed to prepare the SCCM client for a sysprep. I have also included a pop-up window in the event the SCCM client is not properly prepared for the sysprep. The window will stay there until OK is clicked. This gives the admin the capability of either manually deleting the file and registry keys and stopping the ccmexec service, or restarting the build. 



You can download the script from here.



1:  <#  
2:       .SYNOPSIS  
3:            Install SCCM Client  
4:         
5:       .DESCRIPTION  
6:            Uninstall any old client and install the new SCCM client  
7:         
8:       .PARAMETER Build  
9:            Select if this is being executed while building a reference image  
10:         
11:       .PARAMETER ClientInstallationDirectory  
12:            Directory where the client ClientInstallationFile is located  
13:         
14:       .PARAMETER ClientInstallationFile  
15:            SCCM ClientInstallationFile  
16:         
17:       .PARAMETER Install  
18:            A description of the Install parameter.  
19:         
20:       .PARAMETER ManagementPoint  
21:            SCCM Management Point  
22:         
23:       .PARAMETER SMSSiteCode  
24:            SMS Site Code  
25:         
26:       .PARAMETER Uninstall  
27:            A description of the Uninstall parameter.  
28:         
29:       .PARAMETER UsePKICert  
30:            Specifies whether clients use PKI certificate when available  
31:         
32:       .PARAMETER NOCRLCheck  
33:            Specifies that clients do not check the certificate revocation list (CRL) for site systems  
34:         
35:       .PARAMETER Source  
36:            Specifies the source location from which to download installation files. This can be a local or UNC path.  
37:         
38:       .EXAMPLE  
39:            New installation  
40:            powershell.exe -executionpolicy bypass -file SCCMClient.ps1 -Install  
41:              
42:            Uninstall  
43:            powershell.exe -executionpolicy bypass -file SCCMClient.ps1 -Uninstall  
44:              
45:            SCCM/MDT/Sysprep  
46:            powershell.exe -executionpolicy bypass -file SCCMClient.ps1 -Build  
47:            powershell.exe -executionpolicy bypass -file SCCMClient.ps1 -Install -Build  
48:         
49:       .NOTES  
50:            The above examples do not include the $ClientInstallationDirectory and  
51:            the $ClientInsallationFile. I prepopulated the data within the parameter  
52:            definitions below. I also define the $ManagementPoint and $SMSSiteCode. I  
53:            have not tested the $UsePKICert, $NOCRLCheck, or $Source fields as we do  
54:            not use those where I work, therefore I cannot verify if they are valid.  
55:    
56:            ===========================================================================  
57:             Created with:      SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.127  
58:             Created on:        8/2/2016 2:50 PM  
59:             Created by:        Mick Pletcher  
60:             Organization:         
61:             Filename:          SCCMClientInstaller.ps1  
62:            ===========================================================================  
63:    
64:  #>  
65:  [CmdletBinding()]  
66:  param  
67:  (  
68:       [switch]  
69:       $Build,  
70:       [ValidateNotNullOrEmpty()][string]  
71:       $ClientInstallationDirectory = '',  
72:       [ValidateNotNullOrEmpty()][string]  
73:       $ClientInstallationFile = 'ccmsetup.exe',  
74:       [switch]  
75:       $Install,  
76:       [string]  
77:       $ManagementPoint = '',  
78:       [string]  
79:       $SMSSiteCode = '',  
80:       [switch]  
81:       $Uninstall,  
82:       [switch]  
83:       $UsePKICert,  
84:       [switch]  
85:       $NOCRLCheck,  
86:       [string]  
87:       $Source  
88:  )  
89:    
90:    
91:  function Get-MetaData {  
92:  <#  
93:       .SYNOPSIS  
94:            Get File MetaData  
95:         
96:       .DESCRIPTION  
97:            A detailed description of the Get-MetaData function.  
98:         
99:       .PARAMETER FileName  
100:            Name of File  
101:         
102:       .EXAMPLE  
103:            PS C:\> Get-MetaData -FileName 'Value1'  
104:         
105:       .NOTES  
106:            Additional information about the function.  
107:  #>  
108:         
109:       [CmdletBinding()][OutputType([object])]  
110:       param  
111:       (  
112:            [ValidateNotNullOrEmpty()][string]  
113:            $FileName  
114:       )  
115:         
116:       Write-Host "Retrieving File Description Data....." -NoNewline  
117:       $MetaDataObject = New-Object System.Object  
118:       $shell = New-Object -COMObject Shell.Application  
119:       $folder = Split-Path $FileName  
120:       $file = Split-Path $FileName -Leaf  
121:       $shellfolder = $shell.Namespace($folder)  
122:       $shellfile = $shellfolder.ParseName($file)  
123:       $MetaDataProperties = 0..287 | Foreach-Object { '{0} = {1}' -f $_, $shellfolder.GetDetailsOf($null, $_) }  
124:       For ($i = 0; $i -le 287; $i++) {  
125:            $Property = ($MetaDataProperties[$i].split("="))[1].Trim()  
126:            $Property = (Get-Culture).TextInfo.ToTitleCase($Property).Replace(' ', '')  
127:            $Value = $shellfolder.GetDetailsOf($shellfile, $i)  
128:            If ($Property -eq 'Attributes') {  
129:                 switch ($Value) {  
130:                      'A' {  
131:                           $Value = 'Archive (A)'  
132:                      }  
133:                      'D' {  
134:                           $Value = 'Directory (D)'  
135:                      }  
136:                      'H' {  
137:                           $Value = 'Hidden (H)'  
138:                      }  
139:                      'L' {  
140:                           $Value = 'Symlink (L)'  
141:                      }  
142:                      'R' {  
143:                           $Value = 'Read-Only (R)'  
144:                      }  
145:                      'S' {  
146:                           $Value = 'System (S)'  
147:                      }  
148:                 }  
149:            }  
150:            #Do not add metadata fields which have no information  
151:            If (($Value -ne $null) -and ($Value -ne '')) {  
152:                 $MetaDataObject | Add-Member -MemberType NoteProperty -Name $Property -Value $Value  
153:            }  
154:       }  
155:       [string]$FileVersionInfo = (Get-ItemProperty $FileName).VersionInfo  
156:       $SplitInfo = $FileVersionInfo.Split([char]13)  
157:       foreach ($Item in $SplitInfo) {  
158:            $Property = $Item.Split(":").Trim()  
159:            switch ($Property[0]) {  
160:                 "InternalName" {  
161:                      $MetaDataObject | Add-Member -MemberType NoteProperty -Name InternalName -Value $Property[1]  
162:                 }  
163:                 "OriginalFileName" {  
164:                      $MetaDataObject | Add-Member -MemberType NoteProperty -Name OriginalFileName -Value $Property[1]  
165:                 }  
166:                 "Product" {  
167:                      $MetaDataObject | Add-Member -MemberType NoteProperty -Name Product -Value $Property[1]  
168:                 }  
169:                 "Debug" {  
170:                      $MetaDataObject | Add-Member -MemberType NoteProperty -Name Debug -Value $Property[1]  
171:                 }  
172:                 "Patched" {  
173:                      $MetaDataObject | Add-Member -MemberType NoteProperty -Name Patched -Value $Property[1]  
174:                 }  
175:                 "PreRelease" {  
176:                      $MetaDataObject | Add-Member -MemberType NoteProperty -Name PreRelease -Value $Property[1]  
177:                 }  
178:                 "PrivateBuild" {  
179:                      $MetaDataObject | Add-Member -MemberType NoteProperty -Name PrivateBuild -Value $Property[1]  
180:                 }  
181:                 "SpecialBuild" {  
182:                      $MetaDataObject | Add-Member -MemberType NoteProperty -Name SpecialBuild -Value $Property[1]  
183:                 }  
184:            }  
185:       }  
186:         
187:       #Check if file is read-only  
188:       $ReadOnly = (Get-ChildItem $FileName) | Select-Object IsReadOnly  
189:       $MetaDataObject | Add-Member -MemberType NoteProperty -Name ReadOnly -Value $ReadOnly.IsReadOnly  
190:       #Get digital file signature information  
191:       $DigitalSignature = get-authenticodesignature -filepath $FileName  
192:       $MetaDataObject | Add-Member -MemberType NoteProperty -Name SignatureCertificateSubject -Value $DigitalSignature.SignerCertificate.Subject  
193:       $MetaDataObject | Add-Member -MemberType NoteProperty -Name SignatureCertificateIssuer -Value $DigitalSignature.SignerCertificate.Issuer  
194:       $MetaDataObject | Add-Member -MemberType NoteProperty -Name SignatureCertificateSerialNumber -Value $DigitalSignature.SignerCertificate.SerialNumber  
195:       $MetaDataObject | Add-Member -MemberType NoteProperty -Name SignatureCertificateNotBefore -Value $DigitalSignature.SignerCertificate.NotBefore  
196:       $MetaDataObject | Add-Member -MemberType NoteProperty -Name SignatureCertificateNotAfter -Value $DigitalSignature.SignerCertificate.NotAfter  
197:       $MetaDataObject | Add-Member -MemberType NoteProperty -Name SignatureCertificateThumbprint -Value $DigitalSignature.SignerCertificate.Thumbprint  
198:       $MetaDataObject | Add-Member -MemberType NoteProperty -Name SignatureStatus -Value $DigitalSignature.Status  
199:       If (($MetaDataObject -ne "") -and ($MetaDataObject -ne $null)) {  
200:            Write-Host "Success" -ForegroundColor Yellow  
201:       } else {  
202:            Write-Host "Failed" -ForegroundColor Red  
203:       }  
204:       Return $MetaDataObject  
205:  }  
206:    
207:  function Invoke-EXE {  
208:  <#  
209:       .SYNOPSIS  
210:            Install or Uninstall Executable  
211:         
212:       .DESCRIPTION  
213:            A detailed description of the Invoke-EXE function.  
214:         
215:       .PARAMETER InstallerMetaData  
216:            The metadata extracted from the executable  
217:         
218:       .PARAMETER Install  
219:            Specify to Install the application  
220:         
221:       .PARAMETER Uninstall  
222:            Specify to uninstall the application  
223:         
224:       .PARAMETER Executable  
225:            The installation file for installing the application  
226:         
227:       .PARAMETER Switches  
228:            Switches to control the executable file  
229:         
230:       .PARAMETER DisplayName  
231:            Name to be displayed while installing or uninstalling the application  
232:         
233:       .EXAMPLE  
234:            PS C:\> Invoke-EXE  
235:         
236:       .NOTES  
237:            Additional information about the function.  
238:  #>  
239:         
240:       [CmdletBinding()][OutputType([boolean])]  
241:       param  
242:       (  
243:            [object]  
244:            $InstallerMetaData,  
245:            [switch]  
246:            $Install,  
247:            [switch]  
248:            $Uninstall,  
249:            [ValidateNotNullOrEmpty()][string]  
250:            $Executable,  
251:            [string]  
252:            $Switches,  
253:            [string]  
254:            $DisplayName  
255:       )  
256:         
257:       If ($Install.IsPresent) {  
258:            Write-Host "Initiating Installation of"$DisplayName"....." -NoNewline  
259:            $File = $env:windir + "\ccmsetup\ccmsetup.exe"  
260:            $ErrCode = (Start-Process -FilePath $Executable -ArgumentList $Switches -WindowStyle Minimized -Wait -Passthru).ExitCode  
261:            If (($ErrCode -eq 0) -or ($ErrCode -eq 3010)) {  
262:                 Write-Host "Success" -ForegroundColor Yellow  
263:                 If ((Test-Path $File) -eq $true) {  
264:                      Wait-ProcessEnd -ProcessName ccmsetup  
265:                 } else {  
266:                      Write-Host "Failed" -ForegroundColor Red  
267:                      $Failed = $true  
268:                 }  
269:            } else {  
270:                 Write-Host "Failed with error"$ErrCode -ForegroundColor Red  
271:            }  
272:       } elseif ($Uninstall.IsPresent) {  
273:            Write-Host "Uninstalling"$DisplayName"....." -NoNewline  
274:            $File = $env:windir + "\ccmsetup\ccmsetup.exe"  
275:            If ((Test-Path $File) -eq $true) {  
276:                 $ErrCode = (Start-Process -FilePath $Executable -ArgumentList $Switches -WindowStyle Minimized -Wait -Passthru).ExitCode  
277:                 If (($ErrCode -eq 0) -or ($ErrCode -eq 3010)) {  
278:                      Write-Host "Success" -ForegroundColor Yellow  
279:                      If ((Test-Path $File) -eq $true) {  
280:                           Wait-ProcessEnd -ProcessName ccmsetup  
281:                      }  
282:                 } else {  
283:                      $Failed = $true  
284:                      Write-Host "Failed with error"$ErrCode -ForegroundColor Red  
285:                 }  
286:            } else {  
287:                 Write-Host "Not Present" -ForegroundColor Green  
288:            }  
289:       }  
290:       If ($Failed -eq $true) {  
291:            Return $false  
292:       } else {  
293:            Return $true  
294:       }  
295:  }  
296:    
297:  function Remove-File {  
298:  <#  
299:       .SYNOPSIS  
300:            Delete a file with verification  
301:         
302:       .DESCRIPTION  
303:            Delete a file and verify the file no longer exists  
304:         
305:       .PARAMETER Filename  
306:            Name of the file to delete  
307:         
308:       .EXAMPLE  
309:            PS C:\> Remove-File -Filename 'Value1'  
310:         
311:       .NOTES  
312:            Additional information about the function.  
313:  #>  
314:         
315:       [CmdletBinding()][OutputType([boolean])]  
316:       param  
317:       (  
318:            [ValidateNotNullOrEmpty()][string]  
319:            $Filename  
320:       )  
321:         
322:       If ((Test-Path $Filename) -eq $false) {  
323:            Write-Host $Filename" already deleted"  
324:       } else {  
325:            $File = Get-Item $Filename -Force  
326:            Write-Host "Deleting"$File.Name"....." -NoNewline  
327:            If (Test-Path $File) {  
328:                 Remove-Item $File -Force -WarningAction SilentlyContinue -ErrorAction SilentlyContinue | Out-Null  
329:                 If ((Test-Path $Filename) -eq $False) {  
330:                      Write-Host "Success" -ForegroundColor Yellow  
331:                 } else {  
332:                      $Failed = $true  
333:                      Write-Host "Failed" -ForegroundColor Red  
334:                 }  
335:            } else {  
336:                 Write-Host "Not Present" -ForegroundColor Green  
337:            }  
338:       }  
339:       If ($Failed -eq $true) {  
340:            Return $false  
341:       } else {  
342:            Return $true  
343:       }  
344:  }  
345:    
346:  function Remove-RegistryKey {  
347:  <#  
348:       .SYNOPSIS  
349:            Delete registry key  
350:         
351:       .DESCRIPTION  
352:            Delete a registry key. If recurse is selected, all subkeys and values are deleted  
353:         
354:       .PARAMETER RegistryKey  
355:            Registry key to delete  
356:         
357:       .PARAMETER Recurse  
358:            Include all subkeys when deleting the registry key  
359:         
360:       .EXAMPLE  
361:            PS C:\> Remove-RegistryKey -RegistryKey 'Value1'  
362:         
363:       .NOTES  
364:            Additional information about the function.  
365:  #>  
366:         
367:       [CmdletBinding()]  
368:       param  
369:       (  
370:            [ValidateNotNullOrEmpty()][string]  
371:            $RegistryKey,  
372:            [switch]  
373:            $Recurse  
374:       )  
375:         
376:       $RegKey = "Registry::" + $RegistryKey  
377:       If ((Test-Path $RegKey) -eq $false) {  
378:            Write-Host $RegKey" already deleted"  
379:       } else {  
380:            $RegKeyItem = Get-Item $RegKey  
381:            If ($Recurse.IsPresent) {  
382:                 Write-Host "Recursive Deletion of"$RegKeyItem.PSChildName"....." -NoNewline  
383:                 Remove-Item $RegKey -Recurse -Force | Out-Null  
384:            } else {  
385:                 Write-Host "Deleting"$RegKeyItem.PSChildName"....." -NoNewline  
386:                 Remove-Item $RegKey -Force | Out-Null  
387:            }  
388:            If ((Test-Path $RegKey) -eq $false) {  
389:                 Write-Host "Success" -ForegroundColor Yellow  
390:            } else {  
391:                 $Failed = $true  
392:                 Write-Host "Failed" -ForegroundColor Red  
393:            }  
394:       }  
395:       If ($Failed -eq $true) {  
396:            Return $false  
397:       } else {  
398:            Return $true  
399:       }  
400:  }  
401:    
402:  function Set-ConsoleTitle {  
403:  <#  
404:       .SYNOPSIS  
405:            Console Title  
406:         
407:       .DESCRIPTION  
408:            Sets the title of the PowerShell Console  
409:         
410:       .PARAMETER ConsoleTitle  
411:            Title of the PowerShell Console  
412:         
413:       .NOTES  
414:            Additional information about the function.  
415:  #>  
416:         
417:       [CmdletBinding()]  
418:       param  
419:       (  
420:            [Parameter(Mandatory = $true)][String]  
421:            $ConsoleTitle  
422:       )  
423:         
424:       $host.ui.RawUI.WindowTitle = $ConsoleTitle  
425:  }  
426:    
427:  function Suspend-Service {  
428:  <#  
429:       .SYNOPSIS  
430:            Stop specified service  
431:         
432:       .DESCRIPTION  
433:            Stop a specified service and verify it is stopped  
434:         
435:       .PARAMETER Service  
436:            Name of the service  
437:         
438:       .EXAMPLE  
439:            PS C:\> Suspend-Service -Service 'Value1'  
440:         
441:       .NOTES  
442:            Additional information about the function.  
443:  #>  
444:         
445:       [CmdletBinding()][OutputType([boolean])]  
446:       param  
447:       (  
448:            [ValidateNotNullOrEmpty()][string]  
449:            $Service  
450:       )  
451:         
452:       $ServiceStatus = Get-Service $Service -WarningAction SilentlyContinue -ErrorAction SilentlyContinue  
453:       If ($ServiceStatus -ne $null) {  
454:            Write-Host "Stopping"$ServiceStatus.DisplayName"....." -NoNewline  
455:            If ($ServiceStatus.Status -ne 'Stopped') {  
456:                 Stop-Service -Name $Service -WarningAction SilentlyContinue -ErrorAction SilentlyContinue -Force  
457:                 $ServiceStatus = Get-Service $Service -WarningAction SilentlyContinue -ErrorAction SilentlyContinue  
458:                 If ($ServiceStatus.Status -eq 'Stopped') {  
459:                      Write-Host "Success" -ForegroundColor Yellow  
460:                 } else {  
461:                      $Failed = $true  
462:                      Write-Host "Failed" -ForegroundColor Red  
463:                 }  
464:            } else {  
465:                 Write-Host "Service already stopped" -ForegroundColor Yellow  
466:            }  
467:       } else {  
468:            Write-Host $Service"service does not exist"  
469:       }  
470:       If ($Failed -eq $true) {  
471:            Return $false  
472:       } else {  
473:            Return $true  
474:       }  
475:  }  
476:    
477:  function Wait-ProcessEnd {  
478:  <#  
479:       .SYNOPSIS  
480:            Wait for a process to end  
481:         
482:       .DESCRIPTION  
483:            Pause the script until a process no longer exists  
484:         
485:       .PARAMETER ProcessName  
486:            Name of the process  
487:         
488:       .EXAMPLE  
489:                      PS C:\> Wait-ProcessEnd -ProcessName 'Value1'  
490:         
491:       .NOTES  
492:            Additional information about the function.  
493:  #>  
494:         
495:       [CmdletBinding()]  
496:       param  
497:       (  
498:            [ValidateNotNullOrEmpty()][string]  
499:            $ProcessName  
500:       )  
501:         
502:       $Process = Get-Process $ProcessName -ErrorAction SilentlyContinue  
503:       $Process = $Process | Where-Object { $_.ProcessName -eq $ProcessName }  
504:       Write-Host "Waiting for"$Process.Product"to complete....." -NoNewline  
505:       If ($Process -ne $null) {  
506:            Do {  
507:                 Start-Sleep -Seconds 2  
508:                 $Process = Get-Process $ProcessName -ErrorAction SilentlyContinue  
509:                 $Process = $Process | Where-Object { $_.ProcessName -eq $ProcessName }  
510:            }  
511:            While ($Process -ne $null)  
512:            Write-Host "Completed" -ForegroundColor Yellow  
513:       } else {  
514:            Write-Host "Process already completed" -ForegroundColor Yellow  
515:       }  
516:  }  
517:    
518:  cls  
519:  #Set the name of the powershell console  
520:  Set-ConsoleTitle -ConsoleTitle "SCCM Client"  
521:  #Skip over if the install directory and installer file are not defined  
522:  If ($ClientInstallationDirectory -ne $null) {  
523:       If ($ClientInstallationFile -ne $null) {  
524:            If ($ClientInstallationDirectory[$ClientInstallationDirectory.Length - 1] -ne '\') {  
525:                 $ClientInstallationDirectory += '\'  
526:            }  
527:            #Set the location and filename of the SCCM client installer  
528:            $File = $ClientInstallationDirectory + $ClientInstallationFile  
529:            #Get metadata from the SCCM client installer file  
530:            $FileMetaData = Get-MetaData -FileName $File  
531:       }  
532:  }  
533:  #Install parameter is defined  
534:  If ($Install.IsPresent) {  
535:       #Uninstall the SCCM client  
536:       $Parameters = "/uninstall"  
537:       $InstallStatus = Invoke-EXE -Uninstall -DisplayName $FileMetaData.Product -Executable $File -Switches $Parameters  
538:       If ($InstallStatus = $false) {  
539:            $Failed = $true  
540:       }  
541:       #Install the SCCM client  
542:       $Parameters = ""  
543:       If (($ManagementPoint -ne $null) -and ($ManagementPoint -ne "")) {  
544:            $Parameters += "/mp:" + $ManagementPoint  
545:       }  
546:       If (($SMSSiteCode -ne $null) -and ($SMSSiteCode -ne "")) {  
547:            If ($Parameters -ne "") {  
548:                 $Parameters += [char]32  
549:            }  
550:            $Parameters += "SMSSITECODE=" + $SMSSiteCode  
551:       }  
552:       If ($UsePKICert.IsPresent) {  
553:            If ($Parameters -ne "") {  
554:                 $Parameters += [char]32  
555:            }  
556:            $Parameters += "/UsePKICert"  
557:       }  
558:       If ($NOCRLCheck.IsPresent) {  
559:            If ($Parameters -ne "") {  
560:                 $Parameters += [char]32  
561:            }  
562:            $Parameters += "/NOCRLCheck"  
563:       }  
564:       If (($Source -ne $null) -and ($Source -ne "")) {  
565:            If ($Parameters -ne "") {  
566:                 $Parameters += [char]32  
567:            }  
568:            $Parameters += "/source:" + [char]34 + $Source + [char]34  
569:       }  
570:       $InstallStatus = Invoke-EXE -Install -DisplayName $FileMetaData.Product -Executable $File -Switches $Parameters  
571:       If ($InstallStatus -eq $false) {  
572:            $Failed = $true  
573:       }  
574:       #Uninstall parameter is defined  
575:  } elseif ($Uninstall.IsPresent) {  
576:       #Uninstall the SCCM client  
577:       $Parameters = "/Uninstall"  
578:       $InstallStatus = Invoke-EXE -Uninstall -DisplayName $FileMetaData.Product -Executable $File -Switches $Parameters  
579:       If ($InstallStatus -eq $false) {  
580:            $Failed = $true  
581:       }  
582:  }  
583:  #Build parameter is defined  
584:  If ($Build.IsPresent) {  
585:       #Stop the configuration manager client service  
586:       $InstallStatus = Suspend-Service -Service ccmexec  
587:       If ($InstallStatus -eq $false) {  
588:            $Failed = $true  
589:       }  
590:       #Delete the smscfg.ini file  
591:       $InstallStatus = Remove-File -Filename $env:windir"\smscfg.ini"  
592:       If ($InstallStatus -eq $false) {  
593:            $Failed = $true  
594:       }  
595:       #Delete the SCCM certificates from the registry  
596:       $InstallStatus = Remove-RegistryKey -RegistryKey "HKEY_LOCAL_MACHINE\Software\Microsoft\SystemCertificates\SMS\Certificates" -Recurse  
597:       If ($InstallStatus -eq $false) {  
598:            $Failed = $true  
599:       }  
600:  }  
601:  If ($Failed -eq $true) {  
602:       $wshell = New-Object -ComObject Wscript.Shell  
603:       $wshell.Popup("Installation Failed", 0, "Installation Failed", 0x0)  
604:       Exit 1  
605:  } else {  
606:       Exit 0  
607:  }  
608:    

0 comments:

Post a Comment