]> insang Git - newton-cn_pos.git/blob
18d8d1770f32fee7abd0268b76e32dbbea567bcf
[newton-cn_pos.git] /
1 #
2 # Windows Cab Package Provider - Microsoft 2016
3 # This resource manages the packages for a live image.
4 #
5
6 data LocalizedData
7 {
8     # culture="en-US"
9     ConvertFrom-StringData @'
10 SourcePathDoesNotExist=Source does not exist: {0}
11 ConfigurationStarted=The configuration of WindowsPackageCab resource is starting
12 ConfigurationFinished=The configuration of WindowsPackageCab resource has completed
13 FailedToAddPackage=Failed to add package from {0}
14 FailedToRemovePackage=Failed to remove package {0}
15 SourcePathInvalid=Source path is null or empty
16 '@
17 }
18
19 Import-LocalizedData LocalizedData -FileName WindowsPackageCab.Strings.psd1
20
21 [DscResource()]
22 class WindowsPackageCab {
23     
24     # Property: Holds the product name of the package.
25     [DscProperty(Key)]
26     [String] $Name;
27
28     # Property: Makes sure a package is installed/not installed on the image.
29     [DscProperty(Mandatory)]
30     [ValidateSet("Absent","Present")]
31     [String] $Ensure;
32     
33     # Property: Points to the location of a .cab file.
34     [DscProperty(Mandatory)]
35     [String] $SourcePath;
36     
37     # Property: Points the desired location for a log file
38     [DscProperty()]
39     [String] $LogPath;
40
41     WindowsPackageCab()
42     {
43         Import-DscNativeDISMMethods
44     }
45     
46     [void] Set()
47     {
48         Write-Verbose $script:LocalizedData.ConfigurationStarted
49
50         if ([string]::IsNullOrEmpty($this.SourcePath))
51         {
52             Throw-TerminatingError ($script:LocalizedData.SourcePathInvalid)
53         }
54
55         $SourcePathExists = Test-Path -Path $this.SourcePath
56         if (-not $SourcePathExists)
57         {
58             Throw-TerminatingError ($script:LocalizedData.SourcePathDoesNotExist -f $this.SourcePath)
59         }
60         
61         if ($this.Ensure -match 'Present')
62         {
63             Add-CabPackage -PackagePath $this.SourcePath
64         }
65         else
66         {
67             Remove-CabPackage -PackagePath $this.SourcePath
68         }
69
70         Write-Verbose $script:LocalizedData.ConfigurationFinished
71     }
72
73     [bool] Test()
74     {
75         $details = Get-DISMDetailedInstalledPackageInfo -PackageName $this.Name
76
77         $isPackagePresent = Test-PackagePresence -packageInfoDetails $details
78
79         if ($this.Ensure -match 'Present')
80         {
81             return $isPackagePresent
82         }
83         else
84         {
85             return -not $isPackagePresent
86         }
87     }
88
89     [WindowsPackageCab] Get()
90     {
91         $details = Get-DISMDetailedInstalledPackageInfo -PackageName $this.Name
92
93         if ($details -eq $null)
94         {
95             $this.Ensure = 'Absent'
96         }
97         else
98         {
99             $this.Ensure = 'Present'
100         }
101
102         $this.SourcePath = $null
103         $this.LogPath = $null
104
105         return $this
106     }
107 }
108
109 Function Trace-Message
110 {
111     param
112     (
113         [string] $Message
114     )
115
116     Write-Verbose $Message
117
118     if ($this.LogPath)
119     {
120         New-Item -Path $this.LogPath -ErrorAction SilentlyContinue
121         Add-Content -Path $this.LogPath -Value $message
122     }
123 }
124
125 Function Throw-TerminatingError
126 {
127     param
128     (
129         [string] $Message,
130         [System.Management.Automation.ErrorRecord] $ErrorRecord,
131         [string] $ExceptionType
132     )
133     
134     $exception = new-object "System.InvalidOperationException" $Message,$ErrorRecord.Exception
135     $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception,"MachineStateIncorrect","InvalidOperation",$null
136     throw $errorRecord
137 }
138
139 Function Test-PackagePresence
140 {
141     Param 
142     (
143         [Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab.DismDetailedPackageInfo] $packageInfoDetails
144     )
145
146     if (-not $packageInfoDetails)
147     {
148         return $false;
149     }
150
151     if ($packageInfoDetails.PackageState -eq [Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab.DismPackageFeatureState]::DismStateInstalled -or
152         $packageInfoDetails.PackageState -eq [Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab.DismPackageFeatureState]::DismStateInstallPending)
153     {
154         return $true;
155     }
156
157     return $false;
158 }
159
160 Function Get-DISMDetailedInstalledPackageInfo
161 {
162     Param
163     (
164         [string] $PackageName
165     )
166
167     try
168     {
169         $detailedPacketInfo = [Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab.Dism]::new().GetDetailedPackageInfo($PackageName, $this.LogPath)
170     }
171     catch
172     {
173         $detailedPacketInfo = $null
174     }
175
176     return $detailedPacketInfo
177 }
178
179 Function Get-DISMDetailedCabFileInfo
180 {
181     Param
182     (
183         [string] $PackagePath
184     )
185     
186     return [Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab.Dism]::new().GetDetailedCabFileInfo($PackagePath, $this.LogPath)
187 }
188
189 Function Add-CabPackage
190 {
191     Param
192     (
193         [string] $PackagePath
194     )
195
196     try
197     {
198         $dismStatus = [Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab.Dism]::new().AddPackage($PackagePath, $this.LogPath)
199         if ($dismStatus -eq [Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab.DismStatus]::DismStatusRebootRequired)
200         {
201             $global:DSCMachineStatus = 1;
202         }
203         Trace-Message ("-CabPackage successful. PackagePath = $PackagePath")
204     }
205     catch [System.Exception]
206     {
207         Throw-TerminatingError ($script:LocalizedData.FailedToAddPackage -f $this.SourcePath)
208     }
209
210 }
211
212 Function Remove-CabPackage
213 {
214     Param
215     (
216         [string] $PackagePath
217     )
218
219     try
220     {
221         $dismStatus = [Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab.Dism]::new().RemovePackage($PackagePath, $this.LogPath)
222         if ($dismStatus -eq [Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab.DismStatus]::DismStatusRebootRequired)
223         {
224             $global:DSCMachineStatus = 1;
225         }
226         Trace-Message ("Remove-CabPackage successful. PackagePath = $PackagePath")
227     }
228     catch [System.Exception]
229     {
230         Throw-TerminatingError ($script:LocalizedData.FailedToRemovePackage -f $this.SourcePath)
231     }
232 }
233
234 Function Import-DscNativeDISMMethods
235 {
236     if (-not ([System.Management.Automation.PSTypeName]'Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab.Dism').Type)
237     {
238         $source = @"
239 using System;
240 using System.Collections.Generic;
241 using System.IO;
242 using System.Runtime.InteropServices;
243
244 #if CORECLR
245     using Environment = System.Management.Automation.Environment;
246 #else
247 using Environment = System.Environment;
248 #endif
249
250 namespace Microsoft.PowerShell.DesiredStateConfiguration.WindowsPackageCab
251 {
252     #region Native Handlers
253
254     internal enum DismPackageIdentifier
255     {
256         DismPackageNone = 0,
257         DismPackageName = 1,
258         DismPackagePath = 2
259     };
260
261     internal enum DismLogLevel
262     {
263         DismLogErrors = 0,
264         DismLogErrorsWarnings,
265         DismLogErrorsWarningsInfo
266     };
267
268     [StructLayout(LayoutKind.Sequential, Pack = 1)]
269     internal class SystemTime
270     {
271         [MarshalAs(UnmanagedType.U2)]
272         public UInt16 wYear;
273         [MarshalAs(UnmanagedType.U2)]
274         public UInt16 wMonth;
275         [MarshalAs(UnmanagedType.U2)]
276         public UInt16 wDayOfWeek;
277         [MarshalAs(UnmanagedType.U2)]
278         public UInt16 wDay;
279         [MarshalAs(UnmanagedType.U2)]
280         public UInt16 wHour;
281         [MarshalAs(UnmanagedType.U2)]
282         public UInt16 wMinute;
283         [MarshalAs(UnmanagedType.U2)]
284         public UInt16 wSecond;
285         [MarshalAs(UnmanagedType.U2)]
286         public UInt16 wMillisecond;
287     }
288
289     [StructLayout(LayoutKind.Sequential, Pack = 1)]
290     internal class DismPackage
291     {
292         [MarshalAs(UnmanagedType.LPWStr)]
293         internal string PackageName;
294         internal DismPackageFeatureState PackageState;
295         internal DismReleaseType ReleaseType;
296         internal SystemTime InstalledOn;
297     }
298
299     [StructLayout(LayoutKind.Sequential, Pack = 1)]
300     internal class DismPackageDetails
301     {
302         [MarshalAs(UnmanagedType.LPWStr)]
303         public string PackageName;
304         public DismPackageFeatureState PackageState;
305         public DismReleaseType ReleaseType;
306         public SystemTime InstalledOn;
307         public bool Applicable;
308         [MarshalAs(UnmanagedType.LPWStr)]
309         public string Copyright;
310         [MarshalAs(UnmanagedType.LPWStr)]
311         public string Company;
312         public SystemTime CreationTime;
313         [MarshalAs(UnmanagedType.LPWStr)]
314         public string DisplayName;
315         [MarshalAs(UnmanagedType.LPWStr)]
316         public string Description;
317         [MarshalAs(UnmanagedType.LPWStr)]
318         public string InstallClient;
319         [MarshalAs(UnmanagedType.LPWStr)]
320         public string InstallPackageName;
321         public SystemTime LastUpdateTime;
322         [MarshalAs(UnmanagedType.LPWStr)]
323         public string ProductName;
324         [MarshalAs(UnmanagedType.LPWStr)]
325         public string ProductVersion;
326         public DismRestartType RestartRequired;
327         public DismFullyOfflineInstallable FullyOffline;
328         [MarshalAs(UnmanagedType.LPWStr)]
329         public string SupportInformation;
330         public IntPtr CustomPropertyBuffer;
331         [MarshalAs(UnmanagedType.U4)]
332         public UInt32 CustomPropertyCount;
333         public IntPtr FeatureBuffer;
334         [MarshalAs(UnmanagedType.U4)]
335         public UInt32 FeatureCount;
336     }
337
338     [StructLayout(LayoutKind.Sequential, Pack = 1)]
339     internal class DismPackageCustomProperty
340     {
341         [MarshalAs(UnmanagedType.LPWStr)]
342         public string Name;
343         [MarshalAs(UnmanagedType.LPWStr)]
344         public string Value;
345         [MarshalAs(UnmanagedType.LPWStr)]
346         public string Path;
347     }
348
349     [StructLayout(LayoutKind.Sequential, Pack = 1)]
350     public class DismPackageFeature
351     {
352         [MarshalAs(UnmanagedType.LPWStr)]
353         public string FeatureName;
354         public DismPackageFeatureState State;
355     }
356
357     internal class DismNativeMethods
358     {
359         internal static string DismOnlineImage = "DISM_{53BFAE52-B167-4E2F-A258-0A37B57FF845}";
360
361         [DllImport("DismApi.dll")]
362         public static extern int DismCloseSession(uint session);
363
364         [DllImport("DismApi.dll")]
365         public static extern int DismOpenSession(
366             [MarshalAs(UnmanagedType.LPWStr)] string imagePath,
367             [MarshalAs(UnmanagedType.LPWStr)] string windowsDirectory,
368             [MarshalAs(UnmanagedType.LPWStr)] string systemDrive,
369             out uint session
370             );
371
372         [DllImport("DismApi.dll")]
373         public static extern int DismInitialize(
374             DismLogLevel logLevel,
375             [MarshalAs(UnmanagedType.LPWStr)] string logFilePath,
376             [MarshalAs(UnmanagedType.LPWStr)] string scratchDirectory
377             );
378
379         [DllImport("DismApi.dll")]
380         public static extern int DismShutdown();
381
382         [DllImport("DismApi.dll")]
383         public static extern int DismDelete(IntPtr dismStructure);
384
385         [DllImport("DismApi.dll")]
386         public static extern int DismGetPackages(
387             uint session,
388             out IntPtr packageBufPtr,
389             out uint packageCount
390             );
391
392         [DllImport("DismApi.dll")]
393         public static extern int DismGetPackageInfo(
394             uint session,
395             [MarshalAs(UnmanagedType.LPWStr)] string identifier,
396             DismPackageIdentifier packageIdentifier,
397             out IntPtr packageInfo
398             );
399
400         [DllImport("DismApi.dll")]
401         public static extern int DismAddPackage(
402             uint session,
403             [MarshalAs(UnmanagedType.LPWStr)] string packagePath,
404             [MarshalAs(UnmanagedType.Bool)] bool ignoreCheck,
405             [MarshalAs(UnmanagedType.Bool)] bool preventPending,
406             IntPtr cancelEvent,
407             DismProgressCallback progress,
408             IntPtr userData
409             );
410
411         [DllImport("DismApi.dll")]
412         public static extern int DismRemovePackage(
413             uint session,
414             [MarshalAs(UnmanagedType.LPWStr)] string identifier,
415             DismPackageIdentifier packageIdentifier,
416             IntPtr cancelEvent,
417             DismProgressCallback progress,
418             IntPtr userData
419             );
420
421         public delegate void DismProgressCallback(
422             uint current,
423             uint total,
424             IntPtr userData
425             );
426
427         internal static DateTime GetDateTimeFromSystemTime(SystemTime time)
428         {
429             try
430             {
431                 return new DateTime(time.wYear, time.wMonth, time.wDay,
432                     time.wHour, time.wMinute, time.wSecond, DateTimeKind.Local);
433             }
434             catch (ArgumentOutOfRangeException)
435             {
436                 return new DateTime(0, DateTimeKind.Local);
437             }
438         }
439     }
440
441     #endregion Native Handlers
442
443     #region Helper Classes
444
445     internal class DismHandler : IDisposable
446     {
447         #region Private Members
448
449         private readonly string _logPath;
450         private uint _sessionToken;
451         private readonly DismLogLevel _logLevel;
452         private bool _sessionOpened;
453
454         #endregion Private Members
455
456         #region Constructors
457         internal DismHandler(string logPath, DismLogLevel logLevel)
458         {
459             _logPath = logPath;
460             _logLevel = logLevel;
461         }
462
463         internal DismHandler() : this(string.Format("{0}\\dism.log", Path.GetPathRoot(Environment.GetFolderPath(Environment.SpecialFolder.System))), DismLogLevel.DismLogErrorsWarnings) { }
464
465         internal DismHandler(string logPath)
466         {
467             if (!String.IsNullOrEmpty(logPath))
468                 _logPath = logPath;
469             else
470                 _logPath = string.Format("{0}\\dism.log", Path.GetPathRoot(Environment.GetFolderPath(Environment.SpecialFolder.System)));
471
472             _logLevel = DismLogLevel.DismLogErrorsWarnings;
473         }
474         #endregion Constructors
475
476         #region Private Methods
477         private const int CbsInvalidPackage = unchecked((int)0x800f0805);
478         private const int FileNotFound = unchecked((int)0x80070002);
479         private const int CorruptedFile = unchecked((int)0x80070570);
480         private const int InvalidArgument = unchecked((int)0x80070057);
481         private const int SessionReloadRequired = 0x1;
482         private const int MachineRebootRequired = 0xbc2;
483
484         private static void ValidateResult(int hr)
485         {
486             if (hr == 0) return;
487             if (IsSpecialErrorCode(hr)) return;
488
489             switch (hr)
490             {
491                 case CbsInvalidPackage: // 0x800f0805
492                     {
493                         // 0x800f0805 -2146498555 : CBS_E_INVALID_PACKAGE the update package was not a valid CSI update
494                         // when package is queried by name and is not installed
495                         throw new DismInvalidPackageException(string.Format("Dism error code = {0}", hr));
496                     }
497                 case FileNotFound: // 0x80070002
498                     {
499                         // 0x80070002 : -2147024894 E_FILE_NOT_FOUND The system cannot find the file specified.
500                         // when package is queried by path and the file does not exist
501                         throw new FileNotFoundException();
502                     }
503                 case CorruptedFile: // 0x80070570
504                     {
505                         // 0x80070570 : 1392 ERROR_FILE_CORRUPT The file or directory is corrupted and unreadable
506                         // when package file iscorrupted and unreadable
507                         throw new DismInvalidPackageException(string.Format("Dism error code = {0}", hr));
508                     }
509                 case InvalidArgument: // 0x80070057
510                     {
511                         // 0x80070057 -2147024809 : E_INVALIDARG One or more arguments are invalid 
512                         // when package is queried by name and is not installed
513                         throw new DismInvalidPackageException(string.Format("Dism error code = {0}", hr));
514                     }
515                 default:
516                     {
517                         throw new DismException(string.Format("Dism error code = {0}", hr));
518                     }
519             }
520         }
521
522         /// <summary>
523         /// Special Error codes are not failures. They are positive values and often indicate an expected followup operation.
524         /// </summary>
525         /// <param name="errorCode"></param>
526         /// <returns></returns>
527         private static bool IsSpecialErrorCode(int errorCode)
528         {
529             switch (errorCode)
530             {
531                 case SessionReloadRequired:
532                     {
533                         return true;
534                     }
535                 case MachineRebootRequired:
536                     {
537                         return true;
538                     }
539             }
540
541             return false;
542         }
543
544         private static DismStatus GetStatusFromErrorCode(int errorCode)
545         {
546             switch (errorCode)
547             {
548                 case SessionReloadRequired:
549                     {
550                         return DismStatus.DismStatusSuccess;
551                     }
552                 case MachineRebootRequired:
553                     {
554                         return DismStatus.DismStatusRebootRequired;
555                     }
556             }
557
558             return DismStatus.DismStatusSuccess;
559         }
560
561         private void OpenSession()
562         {
563             if (_sessionOpened) return;
564
565             var hr = DismNativeMethods.DismInitialize(_logLevel, _logPath, null);
566             ValidateResult(hr);
567
568             hr = DismNativeMethods.DismOpenSession(DismNativeMethods.DismOnlineImage, null, null, out _sessionToken);
569             ValidateResult(hr);
570
571             _sessionOpened = true;
572         }
573
574         private void CloseSession()
575         {
576             if (!_sessionOpened) return;
577
578             var hr = DismNativeMethods.DismCloseSession(_sessionToken);
579             ValidateResult(hr);
580
581             DismNativeMethods.DismShutdown();
582
583             _sessionOpened = false;
584         }
585
586         private void DeleteDismBuffer(IntPtr buffer)
587         {
588             if (buffer != IntPtr.Zero) DismNativeMethods.DismDelete(buffer);
589             buffer = IntPtr.Zero;
590         }
591
592         #endregion Private Methods
593
594         #region Dispose
595
596         public void Dispose()
597         {
598             Dispose(true);
599             GC.SuppressFinalize(this);
600         }
601
602         protected void Dispose(bool isDisposing)
603         {
604             CloseSession();
605         }
606
607         #endregion Dispose
608
609         #region Core Logic
610
611         internal List<DismPackageInfo> GetInstalledPackages()
612         {
613             OpenSession();
614
615             List<DismPackageInfo> packages = new List<DismPackageInfo>();
616
617             IntPtr pPackagesBuffer;
618             uint numOfPackages = 0;
619
620             var hr = DismNativeMethods.DismGetPackages(_sessionToken, out pPackagesBuffer, out numOfPackages);
621             ValidateResult(hr);
622
623             try
624             {
625                 var pBuffer = pPackagesBuffer;
626                 var originalPackageSize = Marshal.SizeOf(typeof(DismPackage));
627                 for (uint i = 0; i < numOfPackages; i++)
628                 {
629                     try
630                     {
631                         var dismPackage = (DismPackage)Marshal.PtrToStructure(pBuffer, typeof(DismPackage));
632                         if (dismPackage != null)
633                         {
634                             packages.Add(new DismPackageInfo(dismPackage));
635                         }
636                     }
637                     finally
638                     {
639                         pBuffer = new IntPtr(pBuffer.ToInt64() + originalPackageSize);
640                     }
641                 }
642             }
643             finally
644             {
645                 if (pPackagesBuffer != IntPtr.Zero)
646                 {
647                     DismNativeMethods.DismDelete(pPackagesBuffer);
648                 }
649             }
650             return packages;
651         }
652
653         internal DismDetailedPackageInfo GetPackageInfo(string identifier, DismPackageIdentifier packageIdentifier)
654         {
655             OpenSession();
656
657             IntPtr packageInfo;
658
659             var hr = 0;
660
661             hr = DismNativeMethods.DismGetPackageInfo(_sessionToken, identifier, packageIdentifier, out packageInfo);
662             ValidateResult(hr);
663
664             try
665             {
666                 var details = (DismPackageDetails)Marshal.PtrToStructure(packageInfo, typeof(DismPackageDetails));
667                 return extractDismDetailedPackageInfo(details);
668             }
669             finally
670             {
671                 DeleteDismBuffer(packageInfo);
672             }
673         }
674
675         internal DismDetailedPackageInfo extractDismDetailedPackageInfo(DismPackageDetails details)
676         {
677             string PackageName = details.PackageName;
678             DismPackageFeatureState PackageState = details.PackageState;
679             DismReleaseType ReleaseType = details.ReleaseType;
680             DateTime InstalledOn = DismNativeMethods.GetDateTimeFromSystemTime(details.InstalledOn);
681             bool Applicable = details.Applicable;
682             string Copyright = details.Copyright;
683             string Company = details.Company;
684             DateTime CreationTime = DismNativeMethods.GetDateTimeFromSystemTime(details.CreationTime);
685             string DisplayName = details.DisplayName;
686             string Description = details.Description;
687             string InstallClient = details.InstallClient;
688             string InstallPackageName = details.InstallPackageName;
689             DateTime LastUpdateTime = DismNativeMethods.GetDateTimeFromSystemTime(details.LastUpdateTime);
690             string ProductName = details.ProductName;
691             string ProductVersion = details.ProductVersion;
692             DismRestartType RestartRequired = details.RestartRequired;
693             DismFullyOfflineInstallable FullyOffline = details.FullyOffline;
694             string SupportInformation = details.SupportInformation;
695
696             List<DismCustomProperty> CustomProperty = new List<DismCustomProperty>();
697
698             IntPtr currentCustomPropertyPtr = details.CustomPropertyBuffer;
699             for (int i = 0; i < details.CustomPropertyCount; ++i)
700             {
701                 DismCustomProperty customPropertyInstance = new DismCustomProperty(currentCustomPropertyPtr);
702                 CustomProperty.Add(customPropertyInstance);
703                 currentCustomPropertyPtr = new IntPtr(currentCustomPropertyPtr.ToInt64() + Marshal.SizeOf(typeof(DismCustomProperty)));
704             }
705
706             List<DismFeature> Feature = new List<DismFeature>();
707             IntPtr currentFeaturePtr = details.FeatureBuffer;
708             for (int i = 0; i < details.FeatureCount; ++i)
709             {
710                 DismFeature basicFeature = new DismFeature(currentFeaturePtr);
711                 Feature.Add(basicFeature);
712                 currentFeaturePtr = new IntPtr(currentFeaturePtr.ToInt64() + Marshal.SizeOf(typeof(DismPackageFeature)));
713             }
714
715             return new DismDetailedPackageInfo(
716                 PackageName,
717                 PackageState,
718                 ReleaseType,
719                 InstalledOn,
720                 Applicable,
721                 Copyright,
722                 Company,
723                 CreationTime,
724                 DisplayName,
725                 Description,
726                 InstallClient,
727                 InstallPackageName,
728                 LastUpdateTime,
729                 ProductName,
730                 ProductVersion,
731                 RestartRequired,
732                 FullyOffline,
733                 SupportInformation,
734                 CustomProperty,
735                 Feature
736                 );
737         }
738
739         internal DismStatus AddPackage(string packagePath)
740         {
741             OpenSession();
742
743             // Add the package
744             var hr = DismNativeMethods.DismAddPackage(_sessionToken, packagePath, false, false, IntPtr.Zero, null, IntPtr.Zero);
745             ValidateResult(hr);
746             return GetStatusFromErrorCode(hr);
747         }
748
749         internal DismStatus RemoveInstalledPackage(string packagePath)
750         {
751             OpenSession();
752
753             // Remove the package
754             var hr = DismNativeMethods.DismRemovePackage(_sessionToken, packagePath, DismPackageIdentifier.DismPackagePath, IntPtr.Zero, null, IntPtr.Zero);
755             ValidateResult(hr);
756             return GetStatusFromErrorCode(hr);
757         }
758
759         #endregion Core Logic
760     }
761
762     #endregion Helper Classes
763
764     #region Core Logic
765
766     public class DismException : Exception
767     {
768         public DismException(string message) : base(message)
769         {
770         }
771     }
772
773     public class DismInvalidPackageException : Exception
774     {
775         public DismInvalidPackageException(string message)
776         {
777         }
778     }
779
780     public class DismSessionException : Exception
781     {
782         public DismSessionException(string message)
783         {
784         }
785     }
786
787     /// <summary>
788     /// Core Dism class is used directly by the resource and provides a managed interface
789     /// </summary>
790     public class Dism
791     {
792         /// <summary>
793         /// Get a list of installed packages
794         /// </summary>
795         /// <returns>list containining installed packages</returns>
796         public List<DismPackageInfo> GetInstalledPackages(string logPath = null)
797         {
798             using (var dismHandler = new DismHandler(logPath))
799             {
800                 return dismHandler.GetInstalledPackages();
801             }
802         }
803
804         /// <summary>
805         /// Get detailed package info based on unique package name
806         /// </summary>
807         /// <param name="packageName"></param>
808         /// <returns></returns>
809         public DismDetailedPackageInfo GetDetailedPackageInfo(string packageName, string logPath = null)
810         {
811             using (var dismHandler = new DismHandler(logPath))
812             {
813                 return dismHandler.GetPackageInfo(packageName, DismPackageIdentifier.DismPackageName);
814             }
815         }
816
817         /// <summary>
818         /// Get detailed package info based on path to a .cab file
819         /// </summary>
820         public DismDetailedPackageInfo GetDetailedCabFileInfo(string packagePath, string logPath = null)
821         {
822             using (var dismHandler = new DismHandler(logPath))
823             {
824                 return dismHandler.GetPackageInfo(packagePath, DismPackageIdentifier.DismPackagePath);
825             }
826         }
827
828         /// <summary>
829         /// Install windows package from .cab file
830         /// </summary>
831         /// <param name="packagePath"></param>
832         /// <returns></returns>
833         public DismStatus AddPackage(string packagePath, string logPath = null)
834         {
835             using (var dismHandler = new DismHandler(logPath))
836             {
837                 return dismHandler.AddPackage(packagePath);
838             }
839         }
840
841         /// <summary>
842         /// Remove the installed windows package pointed to by the .cab file
843         /// </summary>
844         /// <param name="packagePath"></param>
845         /// <returns></returns>
846         public DismStatus RemovePackage(string packagePath, string logPath = null)
847         {
848             using (var dismHandler = new DismHandler(logPath))
849             {
850                 return dismHandler.RemoveInstalledPackage(packagePath);
851             }
852         }
853
854         private static readonly object SyncObject = new object();
855         private static Dism _instance;
856         public static Dism Instance
857         {
858             get
859             {
860                 if (_instance == null)
861                 {
862                     lock (SyncObject)
863                     {
864                         if (_instance == null)
865                         {
866                             _instance = new Dism();
867                         }
868                     }
869                 }
870
871                 return _instance;
872             }
873         }
874     }
875
876     public class DismDetailedPackageInfo
877     {
878         public string PackageName;
879         public DismPackageFeatureState PackageState;
880         public DismReleaseType ReleaseType;
881         public DateTime InstalledOn;
882         public bool Applicable;
883         public string Copyright;
884         public string Company;
885         public DateTime CreationTime;
886         public string DisplayName;
887         public string Description;
888         public string InstallClient;
889         public string InstallPackageName;
890         public DateTime LastUpdateTime;
891         public string ProductName;
892         public string ProductVersion;
893         public DismRestartType RestartRequired;
894         public DismFullyOfflineInstallable FullyOffline;
895         public string SupportInformation;
896         public List<DismCustomProperty> CustomProperty;
897         public List<DismFeature> Feature;
898
899         internal DismDetailedPackageInfo(
900                 string aPackageName,
901                 DismPackageFeatureState aPackageState,
902                 DismReleaseType aReleaseType,
903                 DateTime aInstalledOn,
904                 bool aApplicable,
905                 string aCopyright,
906                 string aCompany,
907                 DateTime aCreationTime,
908                 string aDisplayName,
909                 string aDescription,
910                 string aInstallClient,
911                 string aInstallPackageName,
912                 DateTime aLastUpdateTime,
913                 string aProductName,
914                 string aProductVersion,
915                 DismRestartType aRestartRequired,
916                 DismFullyOfflineInstallable aFullyOffline,
917                 string aSupportInformation,
918                 List<DismCustomProperty> aCustomProperty,
919                 List<DismFeature> aFeature
920             )
921         {
922             PackageName = aPackageName;
923             PackageState = aPackageState;
924             ReleaseType = aReleaseType;
925             InstalledOn = aInstalledOn;
926             Applicable = aApplicable;
927             Copyright = aCopyright;
928             Company = aCompany;
929             CreationTime = aCreationTime;
930             DisplayName = aDisplayName;
931             Description = aDescription;
932             InstallClient = aInstallClient;
933             InstallPackageName = aInstallPackageName;
934             LastUpdateTime = aLastUpdateTime;
935             ProductName = aProductName;
936             ProductVersion = aProductVersion;
937             RestartRequired = aRestartRequired;
938             FullyOffline = aFullyOffline;
939             SupportInformation = aSupportInformation;
940             CustomProperty = aCustomProperty;
941             Feature = aFeature;
942         }
943     }
944
945     public class DismCustomProperty
946     {
947         public string Name;
948         public string Value;
949         public string Path;
950
951         public DismCustomProperty(
952             string Name,
953             string Value,
954             string Path
955             )
956         {
957             this.Name = Name;
958             this.Value = Value;
959             this.Path = Path;
960         }
961
962         public DismCustomProperty(IntPtr DismPackageCustomPropertyPtr)
963         {
964             DismPackageCustomProperty customProperty = (DismPackageCustomProperty)Marshal.PtrToStructure(DismPackageCustomPropertyPtr, typeof(DismPackageCustomProperty));
965
966             Name = customProperty.Name;
967             Value = customProperty.Value;
968             Path = customProperty.Path;
969         }
970     }
971
972     public class DismFeature
973     {
974         public string FeatureName;
975         public DismFeatureState FeatureState;
976
977         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
978         public DismFeature(IntPtr FeatureBuf)
979         {
980             DismPackageFeature Feature = (DismPackageFeature)Marshal.PtrToStructure(FeatureBuf, typeof(DismPackageFeature));
981
982             SetFeatureState(Feature.State);
983             FeatureName = Feature.FeatureName;
984         }
985
986         public void SetFeatureState(DismPackageFeatureState state)
987         {
988             switch (state)
989             {
990                 case DismPackageFeatureState.DismStateNotPresent:
991                 case DismPackageFeatureState.DismStateStaged:
992                     FeatureState = DismFeatureState.Disabled;
993                     break;
994                 case DismPackageFeatureState.DismStateUninstallPending:
995                     FeatureState = DismFeatureState.DisablePending;
996                     break;
997                 case DismPackageFeatureState.DismStateResolved:
998                     FeatureState = DismFeatureState.DisabledWithPayloadRemoved;
999                     break;
1000                 case DismPackageFeatureState.DismStateInstalled:
1001                     FeatureState = DismFeatureState.Enabled;
1002                     break;
1003                 case DismPackageFeatureState.DismStateInstallPending:
1004                     FeatureState = DismFeatureState.EnablePending;
1005                     break;
1006                 case DismPackageFeatureState.DismStateSuperseded:
1007                     FeatureState = DismFeatureState.Superseded;
1008                     break;
1009                 case DismPackageFeatureState.DismStatePartiallyInstalled:
1010                     FeatureState = DismFeatureState.PartiallyInstalled;
1011                     break;
1012                 default:
1013                     FeatureState = DismFeatureState.Disabled;
1014                     break;
1015             }
1016         }
1017     }
1018
1019     public enum DismPackageFeatureState
1020     {
1021         DismStateNotPresent = 0,
1022         DismStateUninstallPending,
1023         DismStateStaged,
1024         DismStateResolved,
1025         DismStateRemoved = DismStateResolved,
1026         DismStateInstalled,
1027         DismStateInstallPending,
1028         DismStateSuperseded,
1029         DismStatePartiallyInstalled
1030     };
1031
1032     public enum DismFeatureState
1033     {
1034         Disabled = 0,
1035         DisablePending,
1036         Enabled,
1037         EnablePending,
1038         Superseded,
1039         PartiallyInstalled,
1040         DisabledWithPayloadRemoved
1041     }
1042
1043     public enum DismReleaseType
1044     {
1045         DismReleaseTypeCriticalUpdate = 0,
1046         DismReleaseTypeDriver,
1047         DismReleaseTypeFeaturePack,
1048         DismReleaseTypeHotfix,
1049         DismReleaseTypeSecurityUpdate,
1050         DismReleaseTypeSoftwareUpdate,
1051         DismReleaseTypeUpdate,
1052         DismReleaseTypeUpdateRollup,
1053         DismReleaseTypeLanguagePack,
1054         DismReleaseTypeFoundation,
1055         DismReleaseTypeServicePack,
1056         DismReleaseTypeProduct,
1057         DismReleaseTypeLocalPack,
1058         DismReleaseTypeOther
1059     };
1060
1061     public class DismPackageInfo
1062     {
1063         public string Name;
1064         public DismPackageFeatureState PackageState;
1065         public DismReleaseType ReleaseType;
1066         public DateTime InstalledOn;
1067
1068         internal DismPackageInfo(DismPackage package)
1069         {
1070             Name = package.PackageName;
1071             PackageState = package.PackageState;
1072             ReleaseType = package.ReleaseType;
1073             InstalledOn = DismNativeMethods.GetDateTimeFromSystemTime(package.InstalledOn);
1074         }
1075     }
1076
1077     public enum DismRestartType
1078     {
1079         DismRestartNo = 0,
1080         DismRestartPossible = 1,
1081         DismRestartRequired = 2
1082     }
1083
1084     public enum DismFullyOfflineInstallable
1085     {
1086         DismFullyOfflineInstallable = 0,
1087         DismFullyOfflineNotInstallable = 1,
1088         DismFullyOfflineInstallableUndetermined = 2
1089     }
1090
1091     public enum DismStatus
1092     {
1093         DismStatusSuccess = 0,
1094         DismStatusRebootRequired = 1,
1095         DismStatusFailed = 2
1096     };
1097
1098     #endregion Core logic
1099
1100 }
1101
1102
1103 "@
1104
1105         Add-Type -TypeDefinition $source
1106     }
1107 }
1108
1109 Export-ModuleMember -Function ''