CMBuilder.psm1
#Region '.\private\Application.ps1' 0 <# .SYNOPSIS Creates an SCCM Application .DESCRIPTION With a provided (required) configuration file, we can automatically create applications in SCCM, superseeding previous versions #> function Application { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [System.String] $Folder ) Process { Write-Host '[CMBuilder-Application] Creating Application' $NewCMApplication = @{ Name = ('{0} {1} {2}' -f $Configuration.Publisher, $Configuration.Name, $Script:Version) LocalizedApplicationName = if ($Configuration.LocalizedApplicationName) { $Configuration.LocalizedApplicationName } else { ('{0} {1}' -f $Configuration.Publisher, $Configuration.Name) } SoftwareVersion = $Script:Version Publisher = $Configuration.Publisher Description = ('Created by CMBuilder -- {0}' -f $Configuration.Description) ReleaseDate = (Get-Date) AutoInstall = $true # Allow install from Task Sequence } if ($Configuration.AppCatalog) { $NewCMApplication.Add('AppCatalog', $Configuration.AppCatalog) } if ($Configuration.DefaultLanguageId) { $NewCMApplication.Add('DefaultLanguageId', $Configuration.DefaultLanguageId) } if ($Configuration.DisplaySupersedenceInApplicationCatalog) { $NewCMApplication.Add('DisplaySupersedenceInApplicationCatalog', $Configuration.DisplaySupersedenceInApplicationCatalog) } if ($Configuration.IconLocationFile) { $NewCMApplication.Add('IconLocationFile', $Configuration.IconLocationFile) } if ($Configuration.IsFeatured) { $NewCMApplication.Add('IsFeatured', $Configuration.IsFeatured) } if ($Configuration.Keyword) { $NewCMApplication.Add('Keyword', $Configuration.Keyword) } if ($Configuration.LinkText) { $NewCMApplication.Add('LinkText', $Configuration.LinkText) } if ($Configuration.LocalizedDescription) { $NewCMApplication.Add('LocalizedDescription', $Configuration.LocalizedDescription) } if ($Configuration.LocalizedName) { $NewCMApplication.Add('LocalizedName', $Configuration.LocalizedName) } if ($Configuration.OptionalReference) { $NewCMApplication.Add('OptionalReference', $Configuration.OptionalReference) } if ($Configuration.Owner) { $NewCMApplication.Add('Owner', $Configuration.Owner) } if ($Configuration.PrivacyUrl) { $NewCMApplication.Add('PrivacyUrl', $Configuration.PrivacyUrl) } if ($Configuration.SupportContact) { $NewCMApplication.Add('SupportContact', $Configuration.SupportContact) } if ($Configuration.UserDocumentation) { $NewCMApplication.Add('UserDocumentation', $Configuration.UserDocumentation) } Write-Host ('[CMBuilder-Application] New-CMApplication: {0}' -f ($NewCMApplication | Out-String)) $CMApplication = New-CMApplication @NewCMApplication Move-CMObject -FolderPath $Folder -InputObject $CMApplication Write-Output $CMApplication } } #EndRegion '.\private\Application.ps1' 102 #Region '.\private\ApplicationGroup.ps1' 0 function ApplicationGroup { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] $NewCMApplication, [Parameter(Mandatory = $true, Position = 1)] $OldCMApplication ) # Get appgroups that contain the old application $ApplicationGroups = Get-CMApplicationGroup | Where-Object SDMPackageXML -Match ($OldCMApplication.ModelName -split '/')[1] :ApplicationGroup foreach ($Group in $ApplicationGroups) { Write-Host ('[ApplicationGroup] Processing Application Group: {0}' -f $Group.LocalizedDisplayName) $SDKObject = $Group | ConvertTo-CMApplicationGroup Write-Host '[ApplicationGroup] Get names of applications currently in the group' [System.Collections.ArrayList] $ApplicationNames = foreach ($Application in $SDKObject.GroupItems) { $AppNameQuery = "SELECT LocalizedDisplayName FROM SMS_Application WHERE ModelName = '$($Application.ObjectId.Scope)/$($Application.ObjectId.Name)'" Write-Output (Invoke-CMWmiQuery -Query $AppNameQuery).LocalizedDisplayName | Select-Object -Last 1 } # Create an array with the updated application $NewList = $ApplicationNames.Replace($OldCMApplication.LocalizedDisplayName, $NewCMApplication.LocalizedDisplayName) Write-Host '[ApplicationGroup] Updating Application Group' if (-not (Get-CMObjectLockDetails -InputObject $Group).LockState) { Set-CMApplicationGroup -Name $Group.LocalizedDisplayName -RemoveApplication $ApplicationNames -AddApplication $NewList } else { Write-Host ('[ApplicationGroup] CMObject is locked. Skipping.') continue ApplicationGroup } if (Get-Variable -Name 'ModifiedApplicationGroups' -Scope 'Global' -ErrorAction SilentlyContinue) { Write-Host '[ApplicationGroup] ModifiedApplicationGroups variable exists. Adding some info...' $ModifiedApplicationGroups.Add([PSCustomObject] @{ GroupName = $Group.LocalizedDisplayName }) | Out-Null } } } #EndRegion '.\private\ApplicationGroup.ps1' 46 #Region '.\private\Collection.ps1' 0 <# .SYNOPSIS Creates a device collection. .DESCRIPTION Create a device collection on the ConfigMgr Site. #> function Collection { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] $CollectionName, [Parameter(Mandatory = $true, Position = 1)] $LimitingCollectionName, [Parameter(Mandatory = $true, Position = 2)] $SitePath ) Process { $NewColl = @{ LimitingCollectionName = $LimitingCollectionName Name = $CollectionName Comment = 'Collection created by CMBuilder' RefreshSchedule = New-CMSchedule -Start (Get-Date) -DayOfWeek Sunday -RecurCount 1 } Write-Host ('[Collection] Creating collection with args: {0}' -f ($NewColl | Out-String)) $Collection = New-CMDeviceCollection @NewColl $FolderPath = ('{0}:\DeviceCollection\{1}' -f $SiteCode, $SitePath) Write-Host ('[Collection] Moving to: {0}' -f $FolderPath) Move-CMObject -FolderPath $FolderPath -InputObject $Collection $Collection } } #EndRegion '.\private\Collection.ps1' 42 #Region '.\private\Deploy.ps1' 0 function Deploy { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] $NewCMApplication, [Parameter(Position = 1)] $OldCMApplication ) Process { if (($OldCMApplication) -and ($CopyDeployment)) { # Filter out disabled and collections defined in the Configuration $CurrentDeployments = Get-CMApplicationDeployment -InputObject $OldCMApplication | Where-Object { ($_.Enabled -eq $true) -and ($_.CollectionName -notin $Configuration.Deploy.CollectionName) } if ($CurrentDeployments) { Write-Host ('[CMBuilder-Deploy.Copy] Copying previous deployment settings from: {0}' -f ($CurrentDeployments -join '; ') ) Deploy.Copy -CMApplication $NewCMApplication -CurrentDeployments $CurrentDeployments } } if ($Configuration.Deploy) { Write-Host '[CMBuilder-Deploy.Configuration] Deploying to specified collections.' Deploy.Configuration -CMApplication $NewCMApplication } } } #EndRegion '.\private\Deploy.ps1' 30 #Region '.\private\deploy\Deploy.Configuration.ps1' 0 function Deploy.Configuration { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] $CMApplication ) Process { foreach ($Deployment in $Configuration.Deploy) { if (-not ($Collection = Get-CMDeviceCollection -Name $Deployment.CollectionName )) { Write-Verbose ('[CMBuilder-Deploy.Configuration] Creating collection: {0}' -f $Deployment.CollectionName) $Collection = Collection -CollectionName $Deployment.CollectionName -LimitingCollectionName $Deployment.LimitingCollectionName -SitePath $CollectionPath } Write-Host ('[CMBuilder-Deploy.Configuration] Deploying to collection: {0}' -f $Collection.Name) $NewCMApplicationDeployment = @{ InputObject = $CMApplication Collection = $Collection DeployAction = if ($Deployment.DeployAction) { $Deployment.DeployAction } else { 'Install' } DeployPurpose = if ($Deployment.DeployPurpose) { $Deployment.DeployPurpose } else { 'Required' } TimeBaseOn = 'LocalTime' } if ($Deployment.AppCatalog) { $NewCMApplicationDeployment.Add('AppCatalog', $Deployment.AppCatalog) } <# Applies to version 2002 and later. Use this parameter to configure the repair application option when creating a deployment for an application #> if ($Deployment.AllowRepairApp) { $NewCMApplicationDeployment.Add('AllowRepairApp', $Deployment.AllowRepairApp) } <# If you set this parameter to $true, an administrator must approve a request for this application on the device. #> if ($Deployment.ApprovalRequired) { $NewCMApplicationDeployment.Add('ApprovalRequired', $Deployment.ApprovalRequired) } <# Starting in version 2107, set this parameter to $true to enable the application deployment setting for install behaviors. Then use the Add-CMDeploymentTypeInstallBehavior cmdlet to add an executable file to check isn't running for the install to succeed. #> if ($Deployment.AutoCloseExecutable) { $NewCMApplicationDeployment.Add('AutoCloseExecutable', $Deployment.AutoCloseExecutable) } <# Specify a DateTime object for when this deployment is available. To get this object, use the Get-Date built-in cmdlet. Use DeadlineDateTime to specify the deployment assignment, or deadline #> if ($NewCMApplicationDeployment.DeployPurpose -eq 'Required') { if ($Deployment.ImmediateDeployment) { # Become available right now $NewCMApplicationDeployment.Add('AvailableDateTime', (Get-Date)) } else { # Become available at 8AM Monday morning $NewCMApplicationDeployment.Add('AvailableDateTime', (Get-Date -Hour 8 -Minute 0 -Second 0).AddDays((8 - ((Get-Date).DayOfWeek.value__)) % 7)) } } <# Specify an optional comment for this deployment. #> if ($Deployment.Comment) { $NewCMApplicationDeployment.Add('Comment', $Deployment.Comment) } <# Specify a DateTime object for when this deployment is assigned, also known as the deadline. To get this object, use the Get-Date built-in cmdlet. Use -AvailableDateTime to specify when the deployment is available #> if ($NewCMApplicationDeployment.DeployPurpose -eq 'Required') { if ($Deployment.ImmediateDeployment) { # 1 week deadline $NewCMApplicationDeployment.Add('DeadlineDateTime', (Get-Date).AddDays(7)) } else { # 8AM next Monday morning $NewCMApplicationDeployment.Add('DeadlineDateTime', (Get-Date -Hour 8 -Minute 0 -Second 0).AddDays(((8 - ((Get-Date).DayOfWeek.value__)) % 7) + 7)) } } <# Set this parameter to $true to enable delayed enforcement. #> if ($NewCMApplicationDeployment.DeployPurpose -eq 'Required') { if (-not ($Deployment.ImmediateDeployment)) { $NewCMApplicationDeployment.Add('EnableSoftDeadline', $true) } } <# Specifies the percentage of failed application installation that causes an alert. Specify an integer from 1 through 100. To enable this alert, set the CreatAlertBaseOnPercentFailure parameter to $true. #> if ($Deployment.FailParameterValue) { $NewCMApplicationDeployment.Add('FailParameterValue', $Deployment.FailParameterValue) } <# Indicates whether to create an Operations Manager alert if a client fails to install the application. #> if ($Deployment.GenerateScomAlertOnFailure) { $NewCMApplicationDeployment.Add('GenerateScomAlertOnFailure', $Deployment.GenerateScomAlertOnFailure) } <# Indicates whether the deployment takes place even if scheduled outside of a maintenance window. A maintenance window is a specified period of time used for computer maintenance and updates. If this value is $true, Configuration Manager deploys the application even if the scheduled time falls outside the maintenance window. If this value is $false, Configuration Manager doesn't deploy the application outside the window. It waits until it can deploy in an available window. #> if ($Deployment.OverrideServiceWindow) { $NewCMApplicationDeployment.Add('OverrideServiceWindow', $Deployment.OverrideServiceWindow) } <# Indicates whether to enable write filters for embedded devices. For a value of $true, the device commits changes during a maintenance window. This action requires a restart. For a value of $false, the device saves changes in an overlay and commits them later. #> if ($Deployment.PersistOnWriteFilterDevice) { $NewCMApplicationDeployment.Add('PersistOnWriteFilterDevice', $Deployment.PersistOnWriteFilterDevice) } <# When you set CreateAlertBaseOnPercentSuccess to $true, use this parameter to specify a DateTime object. Configuration Manager creates a deployment alert when the threshold is lower than the SuccessParameterValue after this date. #> if ($Deployment.PostponeDateTime) { $NewCMApplicationDeployment.Add('PostponeDateTime', $Deployment.PostponeDateTime) } <# Indicates whether to pre-deploy the application to the primary device of the user. #> if ($Deployment.PreDeploy) { $NewCMApplicationDeployment.Add('PreDeploy', $Deployment.PreDeploy) } <# Indicates whether a computer restarts outside a maintenance window. A maintenance window is a specified period of time used for computer maintenance and updates. If this value is $true, any required restart takes place without regard to maintenance windows. If this value is $false, the computer doesn't restart outside a maintenance window. #> if ($Deployment.RebootOutsideServiceWindow) { $NewCMApplicationDeployment.Add('RebootOutsideServiceWindow', $Deployment.RebootOutsideServiceWindow) } <# When required software is available on the client, set this parameter to $true to replace the default toast notifications with a dialog window. It's false by default. #> if ($Deployment.ReplaceToastNotificationWithDialog) { $NewCMApplicationDeployment.Add('ReplaceToastNotificationWithDialog', $Deployment.ReplaceToastNotificationWithDialog) } <# Indicates whether to send a wake-up packet to computers before the deployment begins. If this value is $true, Configuration Manager attempts to wake a computer from sleep. If this value is $false, it doesn't wake computers from sleep. For computers to wake, you must first configure Wake On LAN. #> if ($Deployment.SendWakeupPacket) { $NewCMApplicationDeployment.Add('SendWakeupPacket', $Deployment.SendWakeupPacket) } <# Specifies the percentage of successful application installation that causes an alert. Specify an integer from 0 through 99. To enable this alert, set the CreateAlertBaseOnPercentSuccess parameter as $true. #> if ($Deployment.SuccessParameterValue) { $NewCMApplicationDeployment.Add('SuccessParameterValue', $Deployment.SuccessParameterValue) } <# For an available deployment, use this parameter to specify the installation deadline to upgrade users or devices that have the superseded application installed. Use DeadlineDateTime to specify a specific time, otherwise it's as soon as possible after the AvailableDateTime. #> if ($Deployment.UpdateSupersedence) { $NewCMApplicationDeployment.Add('UpdateSupersedence', $Deployment.UpdateSupersedence) } <# Indicates whether to allow clients to download content over a metered internet connection after the deadline, which may incur extra expense. #> if ($Deployment.UseMeteredNetwork) { $NewCMApplicationDeployment.Add('UseMeteredNetwork', $Deployment.UseMeteredNetwork) } <# Specifies the type of user notification. DisplayAll: Display in Software Center and show all notifications. DisplaySoftwareCenterOnly: Display in Software Center, and only show notifications of computer restarts. HideAll: Hide in Software Center and all notifications #> if ($Deployment.UserNotification) { $NewCMApplicationDeployment.Add('UserNotification', $Deployment.UserNotification) } Write-Host ('[CMBuilder-Deploy.Configuration] New-CMApplicationDeployment: {0}' -f ($NewCMApplicationDeployment | Out-String)) New-CMApplicationDeployment @NewCMApplicationDeployment if (Get-Variable -Name 'NewDeployments' -Scope 'Global' -ErrorAction SilentlyContinue) { Write-Host '[CMBuilder-Deploy.Configuration] NewDeployments variable exists. Adding some info...' $NewDeployments.Add([PSCustomObject] @{ CollectionName = $Collection.Name Action = $NewCMApplicationDeployment.DeployPurpose }) | Out-Null } } } } #EndRegion '.\private\deploy\Deploy.Configuration.ps1' 219 #Region '.\private\deploy\Deploy.Copy.ps1' 0 function Deploy.Copy { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] $CMApplication, [Parameter(Mandatory = $true, Position = 2)] $CurrentDeployments ) Process { foreach ($Deployment in $CurrentDeployments) { $NewCMApplicationDeployment = @{ InputObject = $CMApplication ApprovalRequired = $Deployment.RequireApproval CollectionID = $Deployment.TargetCollectionID Comment = ('Deployment created by CMBuilder') DeployAction = $Deployment.AssignmentName.Split('_')[-1] EnableMomAlert = $Deployment.DisableMomAlerts EnableSoftDeadline = $Deployment.SoftDeadlineEnabled GenerateScomAlertOnFailure = $Deployment.RaiseMomAlertsOnFailure OverrideServiceWindow = $Deployment.OverrideServiceWindows PersistOnWriteFilterDevice = $Deployment.PersistOnWriteFilterDevices RebootOutsideServiceWindow = $Deployment.RebootOutsideOfServiceWindows SendWakeupPacket = $Deployment.WoLEnabled TimeBaseOn = if ($Deployment.UseGMTTimes) { 'UTC' } else { 'LocalTime' } UpdateSupersedence = $Deployment.UpdateSupersedence UserNotification = if (($Deployment.NotifyUser -eq $true) -and ($Deployment.UserUIExperience -eq $true)) { 'DisplayAll' } elseif (($Deployment.NotifyUser -eq $false) -and ($Deployment.UserUIExperience -eq $true)) { 'DisplaySoftwareCenterOnly' } elseif (($Deployment.NotifyUser -eq $false) -and ($Deployment.UserUIExperience -eq $false)) { 'HideAll' } } switch ($Deployment.OfferTypeID) { 0 { $NewCMApplicationDeployment.Add('DeployPurpose', 'Required') } 2 { $NewCMApplicationDeployment.Add('DeployPurpose', 'Available')} 3 { $NewCMApplicationDeployment.Add('Simulation', $true) } Default { Write-Error ('[CMBuilder-Deploy.Copy] Failed to determine DeployPurpose. Got OfferTypeID of {0}' -f $Deployment.OfferTypeID) } } if ($NewCMApplicationDeployment.DeployPurpose -eq 'Required') { $NewCMApplicationDeployment.Add('AvailableDateTime', (Get-Date -Hour 8 -Minute 0 -Second 0).AddDays((8 - ((Get-Date).DayOfWeek.value__)) % 7)) $NewCMApplicationDeployment.Add('DeadlineDateTime', (Get-Date -Hour 8 -Minute 0 -Second 0).AddDays(((8 - ((Get-Date).DayOfWeek.value__)) % 7) + 7)) } <# OfferFlags are stored as an UINT32 in the SMS_ApplicationAssignment WMI Class. This value is incremented by the value of each OfferFlag turned on. By enumerating over the available flags we find by name which are turned on. #> $OfferFlags = [enum]::GetValues([Microsoft.ConfigurationManagement.ManagementProvider.OfferFlags]) | Where-Object { $_.value__ -band $Deployment.OfferFlags } Write-Output ('[CMBuilder-Deploy.Copy] The following OfferFlags were enumerated: {0}' -f ($OfferFlags -join ' ')) switch ($OfferFlags) { 'Predeploy' { $NewCMApplicationDeployment.Add('PreDeploy', $true) } #'OnDemand' { } 'EnableProcessTermination' { $NewCMApplicationDeployment.Add('AutoCloseExecutable', $true) } 'AllowUsersToRepairApp' { $NewCMApplicationDeployment.Add('AllowRepairApp', $true) } #'RelativeSchedule' { } 'HighImpactDeployment' { $NewCMApplicationDeployment.Add('ReplaceToastNotificationWithDialog', $true) } #'ImplicitUninstall' { } Default { } } Write-Host ('[CMBuilder-Deploy.Copy] New-CMApplicationDeployment: {0}' -f ($NewCMApplicationDeployment | Out-String)) New-CMApplicationDeployment @NewCMApplicationDeployment if (Get-Variable -Name 'NewDeployments' -Scope 'Global' -ErrorAction SilentlyContinue) { Write-Host '[CMBuilder-Deploy.Copy] NewDeployments variable exists. Adding some info...' $NewDeployments.Add([PSCustomObject] @{ CollectionName = $Deployment.CollectionName Action = $NewCMApplicationDeployment.DeployPurpose }) | Out-Null } } } } #EndRegion '.\private\deploy\Deploy.Copy.ps1' 83 #Region '.\private\DeploymentType.ps1' 0 <# .SYNOPSIS Create an SCCM Application .DESCRIPTION With a provided (required) configuration file, we can automatically create applications in SCCM, superseeding previous versions #> function DeploymentType { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] $CMApplication ) Process { foreach ($DeploymentType in $Configuration.DeploymentTypes) { Write-Host '[CMBuilder-Deployment Type] Creating Deployment Type' $AddCMScriptDeploymentType = @{ DeploymentTypeName = $DeploymentType.Name InputObject = $CMApplication Force = $true InstallCommand = $DeploymentType.InstallCommand InstallationBehaviorType = if ($DeploymentType.InstallationBehaviorType) { $DeploymentType.InstallationBehaviorType } else { 'InstallForSystem' } LogonRequirementType = if ($DeploymentType.LogonRequirementType) { $DeploymentType.LogonRequirementType } else { 'WhetherOrNotUserLoggedOn' } UserInteractionMode = if ($DeploymentType.UserInteractionMode) { $DeploymentType.UserInteractionMode } else { 'Hidden' } } if ($DeploymentType.Detection) { $AddCMScriptDeploymentType.Add('AddDetectionClause', (Detection $DeploymentType.Detection)) } elseif ($DeploymentType.DetectionScript) { $AddCMScriptDeploymentType.Add('ScriptFile', $DeploymentType.DetectionScript) switch -regex ($DeploymentType.DetectionScript) { '(?i)(\.ps1$)' { $AddCMScriptDeploymentType.Add('ScriptLanguage', 'PowerShell'); break} '(?i)(\.vbs$)' { $AddCMScriptDeploymentType.Add('ScriptLanguage', 'VBScript'); break} '(?i)(\.js$)' { $AddCMScriptDeploymentType.Add('ScriptLanguage', 'JavaScript'); break} default { Throw 'Unable to match detection script file to language. '} } } else { Throw 'DeploymentType does not contain Detection or ScriptDetection! Failed to create the DeploymentType!' } if ($DeploymentType.ContentLocation) { $AddCMScriptDeploymentType.Add('ContentLocation', $DeploymentType.ContentLocation) } else { $AddCMScriptDeploymentType.Add('ContentLocation', (Join-Path $ContentShare ('{0}\{1}\{2}' -f $Configuration.Publisher, $Configuration.Name, $Script:Version))) } if ($DeploymentType.CacheContent) { $AddCMScriptDeploymentType.Add('CacheContent', $DeploymentType.CacheContent) } if ($DeploymentType.ContentFallback) { $AddCMScriptDeploymentType.Add('ContentFallback', $DeploymentType.ContentFallback) } if ($DeploymentType.DetectionClauseConnector) { $AddCMScriptDeploymentType.Add('DetectionClauseConnector', $DeploymentType.DetectionClauseConnector) } if ($DeploymentType.EnableBranchCache) { $AddCMScriptDeploymentType.Add('EnableBranchCache', $DeploymentType.EnableBranchCache) } if ($DeploymentType.EstimatedRuntimeMins) { $AddCMScriptDeploymentType.Add('EstimatedRuntimeMins', $DeploymentType.EstimatedRuntimeMins) } if ($DeploymentType.Force32Bit) { $AddCMScriptDeploymentType.Add('Force32Bit', $DeploymentType.Force32Bit) } if ($DeploymentType.GroupDetectionClauses) { $AddCMScriptDeploymentType.Add('GroupDetectionClauses', $DeploymentType.GroupDetectionClauses) } if ($DeploymentType.InstallWorkingDirectory) { $AddCMScriptDeploymentType.Add('InstallWorkingDirectory', $DeploymentType.InstallWorkingDirectory) } if ($DeploymentType.LogonRequirementType) { $AddCMScriptDeploymentType.Add('LogonRequirementType', $DeploymentType.LogonRequirementType) } if ($DeploymentType.MaximumRuntimeMins) { $AddCMScriptDeploymentType.Add('MaximumRuntimeMins', $DeploymentType.MaximumRuntimeMins) } if ($DeploymentType.RebootBehavior) { $AddCMScriptDeploymentType.Add('RebootBehavior', $DeploymentType.RebootBehavior) } if ($DeploymentType.RepairCommand) { $AddCMScriptDeploymentType.Add('RepairCommand', $DeploymentType.RepairCommand) } if ($DeploymentType.RepairWorkingDirectory) { $AddCMScriptDeploymentType.Add('RepairWorkingDirectory', $DeploymentType.RepairWorkingDirectory) } if ($DeploymentType.RequireUserInteraction) { $AddCMScriptDeploymentType.Add('RequireUserInteraction', $DeploymentType.RequireUserInteraction) } if ($DeploymentType.SlowNetworkDeploymentMode) { $AddCMScriptDeploymentType.Add('SlowNetworkDeploymentMode', $DeploymentType.SlowNetworkDeploymentMode) } if ($DeploymentType.SourceUpdateProductCode) { $AddCMScriptDeploymentType.Add('SourceUpdateProductCode', $DeploymentType.SourceUpdateProductCode) } if ($DeploymentType.UninstallContentLocation) { $AddCMScriptDeploymentType.Add('UninstallContentLocation', $DeploymentType.UninstallContentLocation) } if ($DeploymentType.UninstallOption) { $AddCMScriptDeploymentType.Add('UninstallOption', $DeploymentType.UninstallOption) } if ($DeploymentType.UninstallWorkingDirectory) { $AddCMScriptDeploymentType.Add('UninstallWorkingDirectory', $DeploymentType.UninstallWorkingDirectory) } if ($DeploymentType.AddRequirement) { $AddCMScriptDeploymentType.Add('AddRequirement', (Requirement $DeploymentType.AddRequirement)) } if ($DeploymentType.RemoveLanguage) { $AddCMScriptDeploymentType.Add('RemoveLanguage', $DeploymentType.RemoveLanguage) } if ($DeploymentType.RemoveRequirement) { $AddCMScriptDeploymentType.Add('RemoveRequirement', $DeploymentType.RemoveRequirement) } if ($DeploymentType.AddLanguage) { $AddCMScriptDeploymentType.Add('AddLanguage', $DeploymentType.AddLanguage) } if ($DeploymentType.Comment) { $AddCMScriptDeploymentType.Add('Comment', $DeploymentType.Comment) } if ($DeploymentType.UninstallCommand) { $AddCMScriptDeploymentType.Add('UninstallCommand', $DeploymentType.UninstallCommand) } Write-Host ('[CMBuilder-Deployment Type] Add-CMScriptDeploymentType: {0}' -f ($AddCMScriptDeploymentType | Out-String)) $NewDeploymentType = Add-CMScriptDeploymentType @AddCMScriptDeploymentType if ($DeploymentType.InstallBehavior) { InstallBehavior -CMApplication $CMApplication -DeploymentType $NewDeploymentType -InstallBehaviorRules $DeploymentType.InstallBehavior } } } } #EndRegion '.\private\DeploymentType.ps1' 178 #Region '.\private\Detection.ps1' 0 function Detection { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] $Detection ) Process { foreach ($Detect in $Detection) { & "Detection.$($Detect.Type)" -Detection $Detect } } } #EndRegion '.\private\Detection.ps1' 15 #Region '.\private\detection\Detection.Directory.ps1' 0 function Detection.Directory { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Detection ) Process { $NewCMDetectionClauseDirectory = @{ DirectoryName = $Detection.DirectoryName Path = $Detection.Path } if ($Detection.PropertyType) { Write-Host '[CMBuilder-Detection.Directory] Detecting specific value' if ($Detection.PropertyType) { $NewCMDetectionClauseDirectory.Add('PropertyType', $Detection.PropertyType) } else { $NewCMDetectionClauseDirectory.Add('PropertyType', 'DateCreated') } $NewCMDetectionClauseDirectory.Add('ExpectedValue', $Detection.ExpectedValue) } else { Write-Host '[CMBuilder-Detection.Directory] Detecting Existence' $NewCMDetectionClauseDirectory.Add('Existence', $true) } Write-Host ('[CMBuilder-Detection.Directory] New-CMDetectionClauseDirectory: {0}' -f ($NewCMDetectionClauseDirectory | Out-String)) $CMDetectionClauseDirectory = New-CMDetectionClauseDirectory @NewCMDetectionClauseDirectory Write-Output $CMDetectionClauseDirectory } } #EndRegion '.\private\detection\Detection.Directory.ps1' 36 #Region '.\private\detection\Detection.File.ps1' 0 function Detection.File { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Detection ) Process { $NewCMDetectionClauseFile = @{ FileName = $Detection.FileName Path = $Detection.Path } if ($Detection.PropertyType) { Write-Host '[CMBuilder-Detection.File] Detecting specific value' $NewCMDetectionClauseFile.Add('PropertyType', $Detection.PropertyType) $NewCMDetectionClauseFile.Add('ExpectedValue', $Detection.ExpectedValue) $NewCMDetectionClauseFile.Add('Value', $true) if ($Detection.ExpressionOperator) { $NewCMDetectionClauseFile.Add('ExpressionOperator', $Detection.ExpressionOperator) } else { $NewCMDetectionClauseFile.Add('ExpressionOperator', 'IsEquals') } } else { Write-Host '[CMBuilder-Detection.File] Detecting Existence' $NewCMDetectionClauseFile.Add('Existence', $true) } if ($Detection.Is32BitApplicationOn64BitSystem) { $NewCMDetectionClauseFile.Add('Is64Bit', $false) } else { $NewCMDetectionClauseFile.Add('Is64Bit', $true) } Write-Host ('[CMBuilder-Detection.File] New-CMDetectionClauseFile: {0}' -f ($NewCMDetectionClauseFile | Out-String)) $CMDetectionClauseFile = New-CMDetectionClauseFile @NewCMDetectionClauseFile Write-Output $CMDetectionClauseFile } } #EndRegion '.\private\detection\Detection.File.ps1' 45 #Region '.\private\detection\Detection.RegistryKey.ps1' 0 function Detection.RegistryKey { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Detection ) Process { $NewCMDetectionClauseRegistryKey = @{ Hive = $Detection.Hive KeyName = $Detection.KeyName Existence = $true } if ($Detection.Is32BitApplicationOn64BitSystem) { $NewCMDetectionClauseRegistryKey.Add('Is64Bit', $false) } else { $NewCMDetectionClauseRegistryKey.Add('Is64Bit', $true) } Write-Host ('[CMBuilder-Detection.RegistryKey] New-CMDetectionClauseRegistryKey: {0}' -f ($NewCMDetectionClauseRegistryKey | Out-String)) $CMDetectionClauseRegistryKey = New-CMDetectionClauseRegistryKey @NewCMDetectionClauseRegistryKey Write-Output $CMDetectionClauseRegistryKey } } #EndRegion '.\private\detection\Detection.RegistryKey.ps1' 29 #Region '.\private\detection\Detection.RegistryKeyValue.ps1' 0 function Detection.RegistryKeyValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Detection ) Process { $NewCMDetectionClauseRegistryKeyValue = @{ Hive = $Detection.Hive KeyName = $Detection.KeyName ValueName = $Detection.ValueName PropertyType = $Detection.PropertyType } if ($Detection.ExpectedValue) { Write-Host '[CMBuilder-Detection.RegistryKeyValue] Detecting specific value' $NewCMDetectionClauseRegistryKeyValue.Add('Value', $true) $NewCMDetectionClauseRegistryKeyValue.Add('ExpectedValue', $Detection.ExpectedValue) if ($Detection.ExpressionOperator) { $NewCMDetectionClauseRegistryKeyValue.Add('ExpressionOperator', $Detection.ExpressionOperator) } else { $NewCMDetectionClauseRegistryKeyValue.Add('ExpressionOperator', 'IsEquals') } } else { Write-Host '[CMBuilder-Detection.RegistryKeyValue] Detecting Existence' $NewCMDetectionClauseRegistryKeyValue.Add('Existence', $Detection.Existence) } if ($Detection.Is32BitApplicationOn64BitSystem) { $NewCMDetectionClauseRegistryKeyValue.Add('Is64Bit', $false) } else { $NewCMDetectionClauseRegistryKeyValue.Add('Is64Bit', $true) } Write-Host ('[CMBuilder-Detection.RegistryKeyValue] New-CMDetectionClauseRegistryKeyValue: {0}' -f ($NewCMDetectionClauseRegistryKeyValue | Out-String)) $CMDetectionClauseRegistryKeyValue = New-CMDetectionClauseRegistryKeyValue @NewCMDetectionClauseRegistryKeyValue Write-Output $CMDetectionClauseRegistryKeyValue } } #EndRegion '.\private\detection\Detection.RegistryKeyValue.ps1' 44 #Region '.\private\detection\Detection.WindowsInstaller.ps1' 0 function Detection.WindowsInstaller { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Detection ) Process { $NewCMDetectionClauseWindowsInstaller = @{} if ($ProductCode) { $NewCMDetectionClauseWindowsInstaller.Add('ProductCode', $ProductCode) } elseif ($Detection.ProductCode) { $NewCMDetectionClauseWindowsInstaller.Add('ProductCode', $Detection.ProductCode) } else { Throw '[CMBuilder-Detection.WindowsInstaller] Failed to find the product code' } if ($Detection.PropertyType) { Write-Host '[CMBuilder-Detection.WindowsInstaller] Detecting specific value' $NewCMDetectionClauseWindowsInstaller.Add('Value', $true) $NewCMDetectionClauseWindowsInstaller.Add('ExpectedValue', $Detection.ExpectedValue) if ($Detection.PropertyType) { $NewCMDetectionClauseWindowsInstaller.Add('PropertyType', $Detection.PropertyType) } else { $NewCMDetectionClauseWindowsInstaller.Add('PropertyType', 'ProductVersion') # Doesn't really matter here, right now it only accepts this single value. } if ($Detection.ExpressionOperator) { $NewCMDetectionClauseWindowsInstaller.Add('ExpressionOperator', $Detection.ExpressionOperator) } else { $NewCMDetectionClauseWindowsInstaller.Add('ExpressionOperator', 'IsEquals') } } else { Write-Host '[CMBuilder-Detection.WindowsInstaller] Detecting Existence' $NewCMDetectionClauseWindowsInstaller.Add('Existence', $Detection.Existence) } Write-Host ('[CMBuilder-Detection.WindowsInstaller] New-CMDetectionClauseWindowsInstaller: {0}' -f ($NewCMDetectionClauseWindowsInstaller | Out-String)) $CMDetectionClauseWindowsInstaller = New-CMDetectionClauseWindowsInstaller @NewCMDetectionClauseWindowsInstaller Write-Output $CMDetectionClauseWindowsInstaller } } #EndRegion '.\private\detection\Detection.WindowsInstaller.ps1' 50 #Region '.\private\Distribute.ps1' 0 function Distribute { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlResultObject] $CMApplication ) foreach ($DistributionPoint in $DistributionPoints) { $StartCMContentDistribution = @{ InputObject = $CMApplication DistributionPointName = $DistributionPoint } Write-Host ('[CMBuilder-Distribute] Start-CMContentDistribution: {0}' -f ($StartCMContentDistribution | Out-String)) Start-CMContentDistribution @StartCMContentDistribution } foreach ($DistributionPointGroup in $DistributionPointGroups) { $StartCMContentDistribution = @{ InputObject = $CMApplication DistributionPointGroupName = $DistributionPointGroup } Write-Host ('[CMBuilder-Distribute] Start-CMContentDistribution: {0}' -f ($StartCMContentDistribution | Out-String)) Start-CMContentDistribution @StartCMContentDistribution } } #EndRegion '.\private\Distribute.ps1' 31 #Region '.\private\Folder.ps1' 0 function Folder { [CmdletBinding()] param ( [Parameter (Mandatory = $true, Position = 0)] [System.String] [ValidateSet('Application', 'SoftwareMetering', 'Package')] $FolderType, [Parameter(Mandatory = $false, Position = 1)] [System.String] $RootOverride ) Process { Write-Progress 'Ensuring Folder Exists' if ($RootOverride) { $FolderPath = '{0}:\{1}\{2}\{3}\{4}' -f $SiteCode, $FolderType, $RootOverride, $Configuration.Publisher, $Configuration.Name } else { $FolderPath = '{0}:\{1}\{2}\{3}' -f $SiteCode, $FolderType, $Configuration.Publisher, $Configuration.Name } Write-Host ('[CMBuilder-Folder] Expected folder path: {0}' -f $FolderPath) if (-not (Test-Path $FolderPath)) { $WorkingVar = $FolderPath # FolderPath needs to be returned complete # Loop until a valid parent is found $MissingParents = do { Write-Output $WorkingVar $WorkingVar = Split-Path $WorkingVar -Parent } While (-not (Test-Path $WorkingVar)) [array]::Reverse($MissingParents) # Create the missing folders foreach ($Parent in $MissingParents) { Write-Host ('[CMPackaer-Folder] Creating Missing Folders: {0}' -f $Parent) New-Item -Path $Parent -ItemType Directory -Force } } Write-Output $FolderPath } } #EndRegion '.\private\Folder.ps1' 46 #Region '.\private\InstallBehavior.ps1' 0 function InstallBehavior { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] $CMApplication, [Parameter(Mandatory = $true, Position = 1)] $DeploymentType, [Parameter(Mandatory = $true, Position = 2)] $InstallBehaviorRules ) process { Write-Host '[CMBuilder-Install Behavior] Adding Install Behavior' $Application = Get-CMApplication -Name $CMApplication.LocalizedDisplayName | ConvertTo-CMApplication $DeploymentTypeIndex = $Application.DeploymentTypes.Title.IndexOf($DeploymentType.DeploymentTypeName) foreach ($Process in $InstallBehaviorRules) { Write-Host ('[CMBuilder-Install Behavior] Adding "{0}" to DeploymentType "{1}"' -f $Process.DisplayName, $DeploymentType.DeploymentTypeName) # Create the process detection $ProcessInfo = [Microsoft.ConfigurationManagement.ApplicationManagement.ProcessInformation]::new() $ProcessInfo.DisplayInfo.Add(@{'DisplayName' = $Process.DisplayName; Language = $NULL }) $ProcessInfo.Name = $Process.Executable # Add the process to the DeploymentType $Application.DeploymentTypes[$DeploymentTypeIndex].Installer.InstallProcessDetection.ProcessList.Add($ProcessInfo) } Write-Host '[CMBuilder-Install Behavior] Commiting Changes' $Application = $Application | ConvertFrom-CMApplication $Application.Put() } } #EndRegion '.\private\InstallBehavior.ps1' 37 #Region '.\private\Metering.ps1' 0 function Metering { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [System.String] $Folder ) process { foreach ($Meter in $Configuration.SoftwareMetering) { if ($Rule = Get-CMSoftwareMeteringRule -ProductName $Meter.ProductName) { Write-Host ('[Metering] Software Metering rule exists: {0}' -f ($Rule.ProductName -join ', ')) } else { Write-Host '[Metering] Software Metering rule does not exist yet' $NewCMSoftwareMeteringRule = @{ ProductName = $Meter.ProductName SiteCode = $SiteCode FileName = $Meter.FileName OriginalFileName = $Meter.FileName FileVersion = if ($Meter.FileVersion) { $Meter.FileVersion } else { '*' } } Write-Host ('[Metering] New-CMSoftwareMeteringRule: {0}' -f ($NewCMSoftwareMeteringRule | Out-String)) $Rule = New-CMSoftwareMeteringRule @NewCMSoftwareMeteringRule Move-CMObject -FolderPath $Folder -InputObject $Rule } } } } #EndRegion '.\private\Metering.ps1' 31 #Region '.\private\PkgSrc.ps1' 0 function PkgSrc { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [IO.DirectoryInfo] $SourceDirectory, # Root folder where content will be stored. [Parameter(Mandatory = $true)] [IO.DirectoryInfo] $ContentRoot ) Write-Host ('[Move-ToPkgSrc] Current Location: {0}' -f (Get-Location)) Write-Host ('[Move-ToPkgSrc] Content Root: {0}' -f $ContentRoot) $ContentSubDir = '{0}\{1}\{2}' -f $Configuration.Publisher, $Configuration.Name, $Version Write-Host ('[Move-ToPkgSrc] Subdir: {0}' -f $ContentSubDir) [IO.DirectoryInfo] $ContentDirectory = Join-Path $ContentRoot $ContentSubDir Write-Host ('[Move-ToPkgSrc] PkgSrc directory: [{0}]' -f $ContentDirectory.FullName) if (-not ($ContentDirectory.Exists)) { Write-Host '[Move-ToPkgSrc] PkgSrc directory does not exist. Creating...' $ContentDirectory = New-Item -Path $ContentDirectory.FullName -ItemType Directory -Force -Verbose } if ($Configuration.WimDeployment) { try { $SourceDirectory = Wim -Directory $SourceDirectory } catch { Write-Warning "Failed to create the Application WIM: $_" continue Project } } else { Write-Host '[Move-ToPkgSrc] Checking for a template directory' if (($Configuration.TemplateDirectory) -and (Test-Path $Configuration.TemplateDirectory)) { Write-Host '[Move-ToPkgSrc] Template directory exists! Copying...' Copy-Item -Path "$($Configuration.TemplateDirectory)\*" -Destination $ContentDirectory.FullName -Recurse -Force -PassThru | Out-Null } } Write-Host ('[Move-ToPkgSrc] Copying Source Directory: {0}' -f $SourceDirectory.FullName) Copy-Item -Path "$($SourceDirectory.FullName)\*" -Destination $ContentDirectory.FullName -Recurse -Force -PassThru | Out-Null if ($Configuration.WimDeployment) { Write-Host '[Move-ToPkgSrc] Cleaning up Source Directory after copy...' Remove-Item $SourceDirectory.FullName -Recurse -Force } } #EndRegion '.\private\PkgSrc.ps1' 51 #Region '.\private\Requirement.ps1' 0 function Requirement { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] $AddRequirement ) Process { foreach ($Requirement in $AddRequirement) { & "Requirement.$($Requirement.Type)" -Requirement $Requirement } } } #EndRegion '.\private\Requirement.ps1' 15 #Region '.\private\requirement\Requirement.ActiveDirectorySiteValue.ps1' 0 function Requirement.ActiveDirectorySiteValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleActiveDirectorySiteValue = @{ InputObject = (Get-CMGlobalCondition -Name 'Active Directory site') Site = $Requirement.Site RuleOperator = $Requirement.RuleOperator } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleActiveDirectorySiteValue.Add('DisableWildcardHandling', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleActiveDirectorySiteValue.Add('ForceWildcardHandling', $true) } Write-Host ('[CMBuilder-Requirement.ActiveDirectorySiteValue] New-CMRequirementRuleActiveDirectorySiteValue: {0}' -f ($NewCMRequirementRuleActiveDirectorySiteValue | Out-String)) $CMRequirementRuleActiveDirectorySiteValue = New-CMRequirementRuleActiveDirectorySiteValue @NewCMRequirementRuleActiveDirectorySiteValue Write-Output $CMRequirementRuleActiveDirectorySiteValue } } #EndRegion '.\private\requirement\Requirement.ActiveDirectorySiteValue.ps1' 31 #Region '.\private\requirement\Requirement.BooleanValue.ps1' 0 function Requirement.BooleanValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleBooleanValue = @{ InputObject = (Get-CMGlobalCondition -Name $Requirement.GlobalCondition) Value = $Requirement.Value } Write-Host ('[CMBuilder-Requirement.BooleanValue] New-CMRequirementRuleBooleanValue: {0}' -f ($NewCMRequirementRuleBooleanValue | Out-String)) $CMRequirementRuleBooleanValue = New-CMRequirementRuleBooleanValue @NewCMRequirementRuleBooleanValue Write-Output $CMRequirementRuleBooleanValue } } #EndRegion '.\private\requirement\Requirement.BooleanValue.ps1' 23 #Region '.\private\requirement\Requirement.CMSiteValue.ps1' 0 function Requirement.CMSiteValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleCMSiteValue = @{ InputObject = (Get-CMGlobalCondition -Name 'Configuration Manager site') Site = $Requirement.Site RuleOperator = $Requirement.RuleOperator } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleCMSiteValue.Add('DisableWildcardHandling', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleCMSiteValue.Add('ForceWildcardHandling', $true) } Write-Host ('[CMBuilder-Requirement.CMSiteValue] New-CMRequirementRuleCMSiteValue: {0}' -f ($NewCMRequirementRuleCMSiteValue | Out-String)) $CMRequirementRuleCMSiteValue = New-CMRequirementRuleCMSiteValue @NewCMRequirementRuleCMSiteValue Write-Output $CMRequirementRuleCMSiteValue } } #EndRegion '.\private\requirement\Requirement.CMSiteValue.ps1' 31 #Region '.\private\requirement\Requirement.CommonValue.ps1' 0 function Requirement.CommonValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleCommonValue = @{ InputObject = (Get-CMGlobalCondition -Name $Requirement.GlobalCondition) Value1 = $Requirement.Value1 RuleOperator = $Requirement.RuleOperator } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleCommonValue.Add('DisableWildcardHandling', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleCommonValue.Add('ForceWildcardHandling', $true) } if ($Requirement.PropertyForAssembly) { $NewCMRequirementRuleCommonValue.Add('PropertyForAssembly', $Requirement.PropertyForAssembly) } if ($Requirement.PropertyForFileFolder) { $NewCMRequirementRuleCommonValue.Add('PropertyForFileFolder', $Requirement.PropertyForFileFolder) } if ($Requirement.Value2) { $NewCMRequirementRuleCommonValue.Add('Value2', $Requirement.Value2) } Write-Host ('[CMBuilder-Requirement.CommonValue] New-CMRequirementRuleCommonValue: {0}' -f ($NewCMRequirementRuleCommonValue | Out-String)) $CMRequirementRuleCommonValue = New-CMRequirementRuleCommonValue @NewCMRequirementRuleCommonValue Write-Output $CMRequirementRuleCommonValue } } #EndRegion '.\private\requirement\Requirement.CommonValue.ps1' 43 #Region '.\private\requirement\Requirement.DeviceOwnershipValue.ps1' 0 function Requirement.DeviceOwnershipValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleDeviceOwnershipValue = @{ InputObject = (Get-CMGlobalCondition -Name 'Ownership' | Where-Object CI_UniqueID -Match "Device_Ownership$($Requirement.DeviceType)`$") OwnershipOption = $Requirement.OwnershipOption RuleOperator = $Requirement.RuleOperator } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleDeviceOwnershipValue.Add('DisableWildcardHandling', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleDeviceOwnershipValue.Add('ForceWildcardHandling', $true) } Write-Host ('[CMBuilder-Requirement.DeviceOwnershipValue] New-CMRequirementRuleDeviceOwnershipValue: {0}' -f ($NewCMRequirementRuleDeviceOwnershipValue | Out-String)) $CMRequirementRuleDeviceOwnershipValue = New-CMRequirementRuleDeviceOwnershipValue @NewCMRequirementRuleDeviceOwnershipValue Write-Output $CMRequirementRuleDeviceOwnershipValue } } #EndRegion '.\private\requirement\Requirement.DeviceOwnershipValue.ps1' 31 #Region '.\private\requirement\Requirement.Existential.ps1' 0 function Requirement.Existential { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleExistential = @{ InputObject = (Get-CMGlobalCondition -Name $Requirement.GlobalCondition) Existential = $Requirement.Existential } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleExistential.Add('DisableWildcardHandling', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleExistential.Add('ForceWildcardHandling', $true) } Write-Host ('[CMBuilder-Requirement.Existential] New-CMRequirementRuleExistential: {0}' -f ($NewCMRequirementRuleExistential | Out-String)) $CMRequirementRuleExistential = New-CMRequirementRuleExistential @NewCMRequirementRuleExistential Write-Output $CMRequirementRuleExistential } } #EndRegion '.\private\requirement\Requirement.Existential.ps1' 30 #Region '.\private\requirement\Requirement.Expression.ps1' 0 function Requirement.Expression { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $GlobalCondition = Get-CMGlobalCondition -AsDcmSdkObject -Name $Requirement.Name if (-not ($GlobalCondition)) { Throw ('[CMBuilder-Requirement.Expression] GlobalCondition {0} not found! This should match the name displayname in the admin console.' -f $Requirement.Name) } if ($GlobalCondition.Rules) { Write-Host ('[CMBuilder-Requirement.Expression] Adding rules from {0}' -f $GlobalCondition.Name) Write-Output $GlobalCondition.Rules } else { Write-Host ('[CMBuilder-Requirement.Expression] Rules not found in "{0}". Verify this is an expression!' -f $GlobalCondition.Name) } } } #EndRegion '.\private\requirement\Requirement.Expression.ps1' 26 #Region '.\private\requirement\Requirement.FileAttributeValue.ps1' 0 function Requirement.FileAttributeValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleFileAttributeValue = @{ InputObject = (Get-CMGlobalCondition -Name $Requirement.GlobalCondition) } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleFileAttributeValue.Add('DisableWildcardHandling', $true) } if ($Requirement.FileArchive) { $NewCMRequirementRuleFileAttributeValue.Add('FileArchive', $true) } if ($Requirement.FileCompressed) { $NewCMRequirementRuleFileAttributeValue.Add('FileCompressed', $true) } if ($Requirement.FileEncrypted) { $NewCMRequirementRuleFileAttributeValue.Add('FileEncrypted', $true) } if ($Requirement.FileHidden) { $NewCMRequirementRuleFileAttributeValue.Add('FileHidden', $true) } if ($Requirement.FileReadOnly) { $NewCMRequirementRuleFileAttributeValue.Add('FileReadOnly', $true) } if ($Requirement.FileSystem) { $NewCMRequirementRuleFileAttributeValue.Add('FileSystem', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleFileAttributeValue.Add('ForceWildcardHandling', $true) } Write-Host ('[CMBuilder-Requirement.FileAttributeValue] New-CMRequirementRuleFileAttributeValue: {0}' -f ($NewCMRequirementRuleFileAttributeValue | Out-String)) $CMRequirementRuleFileAttributeValue = New-CMRequirementRuleFileAttributeValue @NewCMRequirementRuleFileAttributeValue Write-Output $CMRequirementRuleFileAttributeValue } } #EndRegion '.\private\requirement\Requirement.FileAttributeValue.ps1' 53 #Region '.\private\requirement\Requirement.FilePermissionValue.ps1' 0 function Requirement.FilePermissionValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleFilePermissionValue = @{ InputObject = (Get-CMGlobalCondition -Name $Requirement.GlobalCondition) ControlEntry = foreach ($Entry in $Requirement.ControlEntry) { $NewCMFileSystemAccessControlEntry = @{ GroupOrUserName = $Entry.GroupOrUserName AccessOption = $Entry.AccessOption Permission = $Entry.Permission } New-CMFileSystemAccessControlEntry @NewCMFileSystemAccessControlEntry } } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleFilePermissionValue.Add('DisableWildcardHandling', $true) } if ($Requirement.Exclusive) { $NewCMRequirementRuleFilePermissionValue.Add('Exclusive', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleFilePermissionValue.Add('ForceWildcardHandling', $true) } Write-Host ('[CMBuilder-Requirement.FilePermissionValue] New-CMRequirementRuleFilePermissionValue: {0}' -f ($NewCMRequirementRuleFilePermissionValue | Out-String)) $CMRequirementRuleFilePermissionValue = New-CMRequirementRuleFilePermissionValue @NewCMRequirementRuleFilePermissionValue Write-Output $CMRequirementRuleFilePermissionValue } } #EndRegion '.\private\requirement\Requirement.FilePermissionValue.ps1' 41 #Region '.\private\requirement\Requirement.FreeDiskSpaceValue.ps1' 0 function Requirement.FreeDiskSpaceValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleFreeDiskSpaceValue = @{ InputObject = (Get-CMGlobalCondition -Name 'Disk Space') PartitionOption = $Requirement.PartitionOption RuleOperator = $Requirement.RuleOperator Value1 = $Requirement.Value1 } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleFreeDiskSpaceValue.Add('DisableWildcardHandling', $true) } if ($Requirement.DriverLetter) { $NewCMRequirementRuleFreeDiskSpaceValue.Add('DriverLetter', $Requirement.DriverLetter) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleFreeDiskSpaceValue.Add('ForceWildcardHandling', $true) } if ($Requirement.PartitionOption) { $NewCMRequirementRuleFreeDiskSpaceValue.Add('PartitionOption', $Requirement.PartitionOption) } if ($Requirement.Value2) { $NewCMRequirementRuleFreeDiskSpaceValue.Add('Value2', $Requirement.Value2) } Write-Host ('[CMBuilder-Requirement.FreeDiskSpaceValue] New-CMRequirementRuleFreeDiskSpaceValue: {0}' -f ($NewCMRequirementRuleFreeDiskSpaceValue | Out-String)) $CMRequirementRuleFreeDiskSpaceValue = New-CMRequirementRuleFreeDiskSpaceValue @NewCMRequirementRuleFreeDiskSpaceValue Write-Output $CMRequirementRuleFreeDiskSpaceValue } } #EndRegion '.\private\requirement\Requirement.FreeDiskSpaceValue.ps1' 44 #Region '.\private\requirement\Requirement.InputTypeValue.ps1' 0 function Requirement.InputTypeValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleInputTypeValue = @{ InputObject = (Get-CMGlobalCondition -Name 'Input Type') IsTouch = $Requirement.IsTouch } Write-Host ('[CMBuilder-Requirement.InputTypeValue] New-CMRequirementRuleInputTypeValue: {0}' -f ($NewCMRequirementRuleInputTypeValue | Out-String)) $CMRequirementRuleInputTypeValue = New-CMRequirementRuleInputTypeValue @NewCMRequirementRuleInputTypeValue Write-Output $CMRequirementRuleInputTypeValue } } #EndRegion '.\private\requirement\Requirement.InputTypeValue.ps1' 22 #Region '.\private\requirement\Requirement.OperatingSystemLanguageValue.ps1' 0 function Requirement.OperatingSystemLanguageValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleOperatingSystemLanguageValue = @{ InputObject = (Get-CMGlobalCondition -Name 'Operating system language' | Where-Object PlatformType -eq $Requirement.PlatformType) RuleOperator = $Requirement.RuleOperator Culture = foreach ($Culture in $Requirement.Culture) { [System.Globalization.CultureInfo]::GetCultures([System.Globalization.CultureTypes]::AllCultures) | Where-Object Name -eq $Culture } } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleOperatingSystemLanguageValue.Add('DisableWildcardHandling', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleOperatingSystemLanguageValue.Add('ForceWildcardHandling', $true) } if ($Requirement.IsMobile) { $NewCMRequirementRuleOperatingSystemLanguageValue.Add('IsMobile', $true) } Write-Host ('[CMBuilder-Requirement.OperatingSystemLanguageValue] New-CMRequirementRuleOperatingSystemLanguageValue: {0}' -f ($NewCMRequirementRuleOperatingSystemLanguageValue | Out-String)) $CMRequirementRuleOperatingSystemLanguageValue = New-CMRequirementRuleOperatingSystemLanguageValue @NewCMRequirementRuleOperatingSystemLanguageValue Write-Output $CMRequirementRuleOperatingSystemLanguageValue } } #EndRegion '.\private\requirement\Requirement.OperatingSystemLanguageValue.ps1' 37 #Region '.\private\requirement\Requirement.OperatingSystemValue.ps1' 0 function Requirement.OperatingSystemValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleOperatingSystemValue = @{ InputObject = (Get-CMGlobalCondition -Name 'Operating System' | Where-Object PlatformType -EQ $Requirement.PlatformType) RuleOperator = $Requirement.RuleOperator } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleOperatingSystemValue.Add('DisableWildcardHandling', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleOperatingSystemValue.Add('ForceWildcardHandling', $true) } if ($Requirement.Platform) { $NewCMRequirementRuleOperatingSystemValue.Add('Platform', $Requirement.Platform) } if ($Requirement.PlatformString) { $NewCMRequirementRuleOperatingSystemValue.Add('PlatformString', $Requirement.Platform) } if ($Requirement.SelectFullPlatform) { $NewCMRequirementRuleOperatingSystemValue.Add('SelectFullPlatform', $Requirement.Platform) } Write-Host ('[CMBuilder-Requirement.OperatingSystemValue] New-CMRequirementRuleOperatingSystemValue: {0}' -f ($NewCMRequirementRuleOperatingSystemValue | Out-String)) $CMRequirementRuleOperatingSystemValue = New-CMRequirementRuleOperatingSystemValue @NewCMRequirementRuleOperatingSystemValue Write-Output $CMRequirementRuleOperatingSystemValue } } #EndRegion '.\private\requirement\Requirement.OperatingSystemValue.ps1' 42 #Region '.\private\requirement\Requirement.OUValue.ps1' 0 function Requirement.OUValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleOUValue = @{ InputObject = (Get-CMGlobalCondition -Name 'Organizational unit (OU)') RuleOperator = $Requirement.RuleOperator OrganizationalUnit = foreach ($OrganizationalUnit in $Requirement.OrganizationalUnit) { Write-Output ([hashtable] @{ OU = $OrganizationalUnit.OU IsIncludeSubOU = $OrganizationalUnit.IsIncludeSubOU } ) } } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleOUValue.Add('DisableWildcardHandling', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleOUValue.Add('ForceWildcardHandling', $true) } Write-Host ('[CMBuilder-Requirement.OUValue] New-CMRequirementRuleOUValue: {0}' -f ($NewCMRequirementRuleOUValue | Out-String)) $CMRequirementRuleOUValue = New-CMRequirementRuleOUValue @NewCMRequirementRuleOUValue Write-Output $CMRequirementRuleOUValue } } #EndRegion '.\private\requirement\Requirement.OUValue.ps1' 37 #Region '.\private\requirement\Requirement.RegistryKeyPermissionValue.ps1' 0 function Requirement.RegistryKeyPermissionValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleRegistryKeyPermissionValue = @{ InputObject = (Get-CMGlobalCondition -Name $Requirement.GlobalCondition) ControlEntry = foreach ($Entry in $Requirement.ControlEntry) { $NewCMRegistryAccessControlEntry = @{ GroupOrUserName = $Entry.GroupOrUserName AccessOption = $Entry.AccessOption Permission = $Entry.Permission } New-CMRegistryAccessControlEntry @NewCMRegistryAccessControlEntry } } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleRegistryKeyPermissionValue.Add('DisableWildcardHandling', $true) } if ($Requirement.Exclusive) { $NewCMRequirementRuleRegistryKeyPermissionValue.Add('Exclusive', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleRegistryKeyPermissionValue.Add('ForceWildcardHandling', $true) } Write-Host ('[CMBuilder-Requirement.RegistryKeyPermissionValue] New-NewCMRequirementRuleRegistryKeyPermissionValue: {0}' -f ($NewCMRequirementRuleRegistryKeyPermissionValue | Out-String)) $CMRequirementRuleRegistryKeyPermissionValue = New-CMRequirementRuleRegistryKeyPermissionValue @NewCMRequirementRuleRegistryKeyPermissionValue Write-Output $CMRequirementRuleRegistryKeyPermissionValue } } #EndRegion '.\private\requirement\Requirement.RegistryKeyPermissionValue.ps1' 41 #Region '.\private\requirement\Requirement.ScreenResolutionValue.ps1' 0 function Requirement.ScreenResolutionValue { [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true)] [PSCustomObject] $Requirement ) Process { $NewCMRequirementRuleScreenResolutionValue = @{ InputObject = (Get-CMGlobalCondition -Name 'Screen resolution') ScreenResolution = $Requirement.ScreenResolution } if ($Requirement.DisableWildcardHandling) { $NewCMRequirementRuleScreenResolutionValue.Add('DisableWildcardHandling', $true) } if ($Requirement.ForceWildcardHandling) { $NewCMRequirementRuleScreenResolutionValue.Add('ForceWildcardHandling', $true) } Write-Host ('[CMBuilder-Requirement.ScreenResolutionValue] New-CMRequirementRuleScreenResolutionValue: {0}' -f ($NewCMRequirementRuleScreenResolutionValue | Out-String)) $CMRequirementRuleScreenResolutionValue = New-CMRequirementRuleScreenResolutionValue @NewCMRequirementRuleScreenResolutionValue Write-Output $CMRequirementRuleScreenResolutionValue } } #EndRegion '.\private\requirement\Requirement.ScreenResolutionValue.ps1' 30 #Region '.\private\Supersede.ps1' 0 function Supersede { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] $NewCMApplication, [Parameter(Mandatory = $true, Position = 1)] $OldCMApplication ) Process { if ($Configuration.DeploymentTypes.Count -gt 1) { foreach ($DeploymentType in $Configuration.DeploymentTypes) { $NewDeploymentType = Get-CMDeploymentType -InputObject $NewCMApplication -DeploymentTypeName $DeploymentType.Name $OldDeploymentType = Get-CMDeploymentType -InputObject $OldCMApplication -DeploymentTypeName $DeploymentType.Name if ($OldDeploymentType) { $AddCMDeploymentTypeSupersedence = @{ SupersedingDeploymentType = $NewDeploymentType SupersededDeploymentType = $OldDeploymentType } if ($Configuration.SupersedeUninstall) { Write-Host '[CMBuilder-Supersede] Supersede uninstall flag set' $AddCMDeploymentTypeSupersedence.Add('IsUninstall', $true) } Write-Host ('[CMBuilder-Supersede] Add-CMDeploymentTypeSupersedence: {0}' -f ($AddCMDeploymentTypeSupersedence | Out-String)) Add-CMDeploymentTypeSupersedence @AddCMDeploymentTypeSupersedence } else { Write-Host ('[CMBuilder-Supersede] Unable to find a Old DeploymentType to supersede. Possible new deploymenttype added.') } } } else { $NewDeploymentType = Get-CMDeploymentType -InputObject $NewCMApplication $OldDeploymentType = Get-CMDeploymentType -InputObject $OldCMApplication $AddCMDeploymentTypeSupersedence = @{ SupersedingDeploymentType = $NewDeploymentType SupersededDeploymentType = $OldDeploymentType } if ($Configuration.SupersedeUninstall) { Write-Host '[CMBuilder-Supersede] Supersede uninstall flag set' $AddCMDeploymentTypeSupersedence.Add('IsUninstall', $true) } Write-Host ('[CMBuilder-Supersede] Add-CMDeploymentTypeSupersedence: {0}' -f ($AddCMDeploymentTypeSupersedence | Out-String)) Add-CMDeploymentTypeSupersedence @AddCMDeploymentTypeSupersedence } } } #EndRegion '.\private\Supersede.ps1' 54 #Region '.\private\TaskSequence.ps1' 0 function TaskSequence { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] $NewCMApplication, [Parameter(Mandatory = $true, Position = 1)] $OldCMApplication ) # Get the task sequence package ids that reference the old application $ApplicationQuery = ('select PackageID from SMS_TaskSequenceAppReferencesInfo where RefAppModelName like "{0}"' -f $OldCMApplication.ModelName) $TaskSequenceIDs = (Invoke-CMWmiQuery -Query $ApplicationQuery).PackageID :TaskSequence foreach ($PackageID in $TaskSequenceIDs) { $TaskSequence = Get-CMTaskSequence -TaskSequencePackageId $PackageID -Fast Write-Host ('[TaskSequence] Processing Task Sequence: {0}' -f $TaskSequence.Name) if (-not ($TaskSequence.TsEnabled)) { Write-Verbose 'Task sequence is disabled. Skipping...' continue TaskSequence } if ($TaskSequence.Name -in $TaskSequenceSkipList) { Write-Host 'Task sequence is in the opt out list. Skipping...' continue TaskSequence } $InstallApplicationSteps = Get-CMTSStepInstallApplication -InputObject $TaskSequence foreach ($TaskSequenceStep in $InstallApplicationSteps) { $ApplicationList = $TaskSequenceStep.ApplicationName.Split(",") if ($OldCMApplication.ModelName -in $ApplicationList) { Write-Host '[TaskSequence] Old application is in this task sequence' $ModelNames = $ApplicationList.Replace($OldCMApplication.ModelName, $NewCMApplication.ModelName) if (-not (Get-CMObjectLockDetails -InputObject $TaskSequence).LockState) { Set-CMTSStepInstallApplication -InputObject $TaskSequence -StepName $TaskSequenceStep.Name -Application ($ModelNames | ForEach-Object { Get-CMApplication -ModelName $_ }) } else { Write-Host '[TaskSequence] CMObject locked. Skipping.' continue TaskSequence } if (Get-Variable -Name 'ModifiedTaskSequences' -Scope 'Global' -ErrorAction SilentlyContinue) { Write-Host '[TaskSequence] ModifiedTaskSequences variable exists. Adding some info...' $ModifiedTaskSequences.Add([PSCustomObject] @{ TSName = $TaskSequence.Name TSStep = $TaskSequenceStep.Name }) | Out-Null } } } } } #EndRegion '.\private\TaskSequence.ps1' 58 #Region '.\private\Wim.ps1' 0 function Wim { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [IO.DirectoryInfo] $Directory ) Write-Host '[Wim] Creating a new source directory' <# New Source Directory will be used to house the Invoke-WimAppDeploy.ps1 and the Application.wim files. $Directory and all of it's contents, which may include template directory contents, will be deleted at the completion of this function to clean up space on servers #> [IO.DirectoryInfo] $NewSourceDirectory = Join-Path $env:Temp (New-Guid).Guid if (-not ($NewSourceDirectory.Exists)) { Write-Host '[Wim] New source directory directory does not exist. Creating...' $NewSourceDirectory = New-Item $NewSourceDirectory.FullName -ItemType Directory -Force } [IO.DirectoryInfo] $ApplicationFiles = Join-Path $Directory.FullName 'Application Files' if (-not ($ApplicationFiles.Exists)) { Write-Host '[Wim] New Application Files directory directory does not exist. Creating...' $ApplicationFiles = New-Item $ApplicationFiles.FullName -ItemType Directory -Force } if (($Configuration.TemplateDirectory) -and (Test-Path $Configuration.TemplateDirectory)) { Copy-Item -Path "$($Configuration.TemplateDirectory)\*" -Destination $ApplicationFiles.FullName -Recurse -Force | Out-Null } Write-Host '[Wim] Moving files from Source Directory to the Application Files directory...' foreach ($File in (Get-ChildItem $Directory.FullName -Exclude 'Invoke-WimAppDeploy.ps1', 'Settings.json', 'WimAppDeploy', 'Source Files', 'Application Files')) { Write-Host ('[Wim] Moving item: {0}' -f $File.Name) Move-Item -Path $File.FullName -Destination $ApplicationFiles.FullName -Force -ErrorAction Stop } Write-Host '[Wim] Setting up all of the WimAppDeploy files' $GLWimAppDeploy = Join-Path $Directory.FullName 'Invoke-WimAppDeploy.ps1' Write-Host ('[Wim] GLWimAppDeploy potential path: {0}' -f $GLWimAppDeploy) if (Test-Path $GLWimAppDeploy) { Copy-Item $GLWimAppDeploy -Destination $NewSourceDirectory.FullName -Force } $GLSettingsFile = Join-Path $Directory.FullName 'Settings.json' Write-Host ('[Wim] GLSettingsFile potential path: {0}' -f $GLSettingsFile) if (Test-Path $GLSettingsFile) { Copy-Item $GLSettingsFile -Destination $NewSourceDirectory.FullName -Force } $GLWimAppDeployDir = Join-Path $Directory.FullName 'WimAppDeploy' Write-Host ('[Wim] GLWimAppDeployDir potential path: {0}' -f $GLWimAppDeployDir) if (Test-Path $GLWimAppDeployDir) { Copy-Item $GLWimAppDeployDir -Destination $NewSourceDirectory.FullName -Force -Recurse } $GLSourceFilesDirectory = Join-Path $Directory.FullName 'Source Files' Write-Host ('[Wim] GLSourceFilesDirectory potential path: {0}' -f $GLSourceFilesDirectory) if (Test-Path $GLSourceFilesDirectory) { Copy-Item $GLSourceFilesDirectory -Destination $NewSourceDirectory.FullName -Force -Recurse } Write-Host '[Wim] Generating the WIM file' [IO.FileInfo] $ImageFile = Join-Path $NewSourceDirectory.FullName 'Application.wim' Start-Process 'dism.exe' -ArgumentList "/Capture-Image /ImageFile:""$($ImageFile.FullName)"" /CaptureDir:""$($ApplicationFiles.FullName)"" /Name:""$($Configuration.Name)"" /Description:""$($Configuration.Name)"" /Compress:fast" -Wait -NoNewWindow -ErrorAction 'Stop' Write-Host ('[Wim] WIM file filepath: {0}' -f ($ImageFile.FullName)) Write-Host ('[Wim] WIM file created: {0}' -f ($ImageFile.Exists)) if (-not ($ImageFile.Exists)) { Throw '[Wim] Failed to locate the Application.wim file' } return $NewSourceDirectory } #EndRegion '.\private\Wim.ps1' 82 #Region '.\public\Start-Builder.ps1' 0 function Start-Builder { [CmdletBinding()] param ( # Valid path to the configuration file. Currently supported xml and yaml [Parameter(Mandatory = $true, Position = 0)] [ValidateScript({ $_.Exists })] [IO.FileInfo] $ConfigFile, # Directory containing files needed for the Application to install. [Parameter(Mandatory = $true)] [IO.DirectoryInfo] $SourceDirectory, # Configuration Manager FQDN ex: configmgr.contoso.com [Parameter(Mandatory = $true)] [string] $SiteServerFQDN, # Configuration manager site code ex: CON [Parameter(Mandatory)] [string] $SiteCode, # Network share accessable by configmgr to store content. [Parameter(Mandatory)] [IO.DirectoryInfo] $ContentShare, # Optional array of distribution points to distribute content too. [Parameter()] [string[]] $DistributionPoints, # Optional array of distribution point groups to distribute too. [Parameter()] [string[]] $DistributionPointGroups, # Specify a child directory to store applications in. [Parameter()] [string] $ApplicationFolder, # Specify a child directory to create collections under. [Parameter()] [string] $CollectionFolder, # Update old application referenced in a task sequence [Parameter()] [switch] $UpdateTaskSequences, # List of Task sequence that will be excluded from having the old application updated. [Parameter()] [string[]] $TaskSequenceSkipList, # Copy the deployment from the old application to the new application. [Parameter()] [switch] $CopyDeployment ) Begin { $ErrorActionPreference = 'Stop' try { Import-Module (Join-Path (Split-Path $env:SMS_ADMIN_UI_PATH -Parent) 'ConfigurationManager.psd1') } catch { throw 'The specified module ''ConfigurationManager'' was not loaded because no valid module file was found. Is the admin console installed?' } # Read ConfigFile switch ($ConfigFile.Extension) { '.xml' { $XML = New-Object xml $XML.PreserveWhitespace = $true $XML.Load($ConfigFile.FullName) $Script:Configuration = $XML.package } '.yaml' { $Script:Configuration = Get-Content $ConfigFile.FullName | ConvertFrom-Yaml } Default { throw 'Invalid configuration file. '} } $Script:Version = $Configuration.SoftwareVersion Write-Verbose ('[CMBuilder] Configuration: {0}' -f ($Configuration | Out-String)) Write-Host '[CMBuilder] Importing Configuration Manager PSModule' Write-Host '[CMBuilder] Ensuring Configuration Manager Drive is mapped' if (-not (Get-PSDrive -Name $SiteCode -ErrorAction SilentlyContinue)) { New-PSDrive -Name $SiteCode -PSProvider "CMSite" -Root $SiteServerFQDN -Description "SCCM Site" | Out-Null } } Process { Write-Host '[CMBuilder] Moving ' Write-Host ('[CMBuilder] Source Directory: {0}' -f $SourceDirectory) PkgSrc -SourceDirectory $SourceDirectory -ContentRoot $ContentShare Push-Location ('{0}:' -f $SiteCode) Write-Host '[CMBuilder] Creating/Detecting application folder' if ($ApplicationFolder) { $Folder = Folder -FolderType 'Application' -RootOverride $ApplicationFolder } else { $Folder = Folder -FolderType 'Application' } $ContainerNodeID = (Get-Item $Folder).ContainerNodeID Write-Host ('[CMBuilder] Folder: {0}' -f $Folder) Write-Host ('[CMBuilder] Folder ContainerNodeId: {0}' -f $ContainerNodeID) Write-Host '[CMBuilder] Creating application' $CMApplication = Application -Folder $Folder $DeploymentType = DeploymentType -CMApplication $CMApplication Write-Host '[CMBuilder] Distributing Application to DPs' Distribute -CMApplication $CMApplication Write-Host '[CMBuilder] Detecting older versions' $instanceKeys = (Invoke-CMWmiQuery -Query "select InstanceKey from SMS_ObjectContainerItem where ObjectType='6000' and ContainerNodeID='$ContainerNodeID'").instanceKey $ExistingApplications = foreach ($Key in $instanceKeys) { Get-CMApplication -ModelName $Key } Write-Host ('[CMBuilder] Detected {0} applications' -f $ExistingApplications.Count) if ($ExistingApplications) { $Applications = $ExistingApplications | Where-Object { ($_.SoftwareVersion -ne $Script:Version) -and ($_.SoftwareVersion -notmatch '[a-z]') } foreach ($Application in $Applications) { if (-not ($Application.SoftwareVersion)) { continue } $VersionInfo = [Version]$Application.SoftwareVersion if (($Null -eq $LatestApplication) -or ($VersionInfo -ge [Version]$LatestApplication.SoftwareVersion)) { $LatestApplication = $Application } } if ($LatestApplication) { Write-Host '[CMBuilder] Found a previous version. Superseding it!' Write-Host ('[CMBuilder] Old version: {0}; New Version: {1}' -f $LatestApplication.SoftwareVersion, $Script:Version) Supersede -NewCMApplication $CMApplication -OldCMApplication $LatestApplication if ((-not $Configuration.NoDeploy) -and ($UpdateTaskSequences)) { Write-Host '[CMBuilder] Updating Task Sequences' TaskSequence -NewCMApplication $CMApplication -OldCMApplication $LatestApplication ApplicationGroup -NewCMApplication $CMApplication -OldCMApplication $LatestApplication } } } if (-not ($Configuration.NoDeploy)) { Write-Host '[CMBuilder] Deploying Application' Deploy -NewCMApplication $CMApplication -OldCMApplication $LatestApplication } else { Write-Warning '[CMBuilder] Configuration has NoDeploy key set. This application will not be automatically deployed.' } if ($Configuration.SoftwareMetering) { $MeteringFolder = Folder -FolderType 'SoftwareMetering' Metering -Folder $MeteringFolder } } End { #We leave after as to not cause any trouble, perhaps unnecessary Pop-Location } } #EndRegion '.\public\Start-Builder.ps1' 193 |