application-workloads/sccm/sccm-currentbranch/DSC/InstallCSForHierarchy.ps1 (416 lines of code) (raw):
Param($DomainFullName,$CM,$CMUser,$Role,$ProvisionToolPath,$LogFolder,$PSName,$PSRole)
$DName = $DomainFullName.Split(".")[0]
$PSComputerAccount = "$DName\$PSName$"
$SMSInstallDir="C:\Program Files\Microsoft Configuration Manager"
$logpath = $ProvisionToolPath+"\InstallSCCMlog.txt"
$ConfigurationFile = Join-Path -Path $ProvisionToolPath -ChildPath "$Role.json"
$Configuration = Get-Content -Path $ConfigurationFile | ConvertFrom-Json
$Configuration.InstallSCCM.Status = 'Running'
$Configuration.InstallSCCM.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
$Configuration | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force
$cmpath = "c:\$CM.exe"
$cmsourceextractpath = "c:\$CM"
if(!(Test-Path $cmpath))
{
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Copying SCCM installation source..." | Out-File -Append $logpath
$cmurl = "https://go.microsoft.com/fwlink/?linkid=2093192"
Invoke-WebRequest -Uri $cmurl -OutFile $cmpath
if(!(Test-Path $cmsourceextractpath))
{
New-Item -ItemType Directory -Path $cmsourceextractpath
Start-Process -WorkingDirectory ($cmsourceextractpath) -Filepath ($cmpath) -ArgumentList ('/s') -wait
}
}
$cmsourcepath = (Get-ChildItem -Path $cmsourceextractpath | ?{$_.Name.ToLower().Contains("cd.")}).FullName
$CMINIPath = "$cmsourceextractpath\HierarchyCS.ini"
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Check ini file." | Out-File -Append $logpath
$cmini = @'
[Identification]
Action=InstallCAS
[Options]
ProductID=EVAL
SiteCode=%Role%
SiteName=%Role%
SMSInstallDir=%InstallDir%
SDKServer=%MachineFQDN%
PrerequisiteComp=0
PrerequisitePath=%cmsourcepath%\REdist
MobileDeviceLanguage=0
AdminConsole=1
JoinCEIP=0
[SQLConfigOptions]
SQLServerName=%SQLMachineFQDN%
DatabaseName=%SQLInstance%CM_%Role%
SQLSSBPort=4022
SQLDataFilePath=%SQLDataFilePath%
SQLLogFilePath=%SQLLogFilePath%
[CloudConnectorOptions]
CloudConnector=1
CloudConnectorServer=%MachineFQDN%
UseProxy=0
ProxyName=
ProxyPort=
[SystemCenterOptions]
SysCenterId=
[HierarchyExpansionOption]
'@
$inst = (get-itemproperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server').InstalledInstances[0]
$p = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL').$inst
$sqlinfo = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$p\$inst"
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] ini file exist." | Out-File -Append $logpath
$cmini = $cmini.Replace('%InstallDir%',$SMSInstallDir)
$cmini = $cmini.Replace('%MachineFQDN%',"$env:computername.$DomainFullName")
$cmini = $cmini.Replace('%SQLMachineFQDN%',"$env:computername.$DomainFullName")
$cmini = $cmini.Replace('%Role%',$Role)
$cmini = $cmini.Replace('%SQLDataFilePath%',$sqlinfo.DefaultData)
$cmini = $cmini.Replace('%SQLLogFilePath%',$sqlinfo.DefaultLog)
$cmini = $cmini.Replace('%CM%',$CM)
$cmini = $cmini.Replace('%cmsourcepath%',$cmsourcepath)
if(!(Test-Path $cmsourcepath\Redist))
{
New-Item $cmsourcepath\Redist -ItemType directory | Out-Null
}
if($inst.ToUpper() -eq "MSSQLSERVER")
{
$cmini = $cmini.Replace('%SQLInstance%',"")
}
else
{
$tinstance = $inst.ToUpper() + "\"
$cmini = $cmini.Replace('%SQLInstance%',$tinstance)
}
$CMInstallationFile = "$cmsourcepath\SMSSETUP\BIN\X64\Setup.exe"
$cmini > $CMINIPath
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Installing.." | Out-File -Append $logpath
Start-Process -Filepath ($CMInstallationFile) -ArgumentList ('/NOUSERINPUT /script "' + $CMINIPath + '"') -wait
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Finished installing CM." | Out-File -Append $logpath
Remove-Item $CMINIPath
$Configuration.InstallSCCM.Status = 'Completed'
$Configuration.InstallSCCM.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
$Configuration | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force
#Upgrade SCCM
$Configuration.UpgradeSCCM.Status = 'Running'
$Configuration.UpgradeSCCM.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
$Configuration | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force
Start-Sleep -Seconds 120
$logpath = $ProvisionToolPath+"\UpgradeCMlog.txt"
$SiteCode = Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\SMS\Identification' -Name 'Site Code'
$ProviderMachineName = $env:COMPUTERNAME+"."+$DomainFullName # SMS Provider machine name
# Customizations
$initParams = @{}
if($ENV:SMS_ADMIN_UI_PATH -eq $null)
{
$ENV:SMS_ADMIN_UI_PATH = "C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\i386"
}
# Import the ConfigurationManager.psd1 module
if((Get-Module ConfigurationManager) -eq $null) {
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" @initParams
}
# Connect to the site's drive if it is not already present
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Setting PS Drive..." | Out-File -Append $logpath
New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams
while((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null)
{
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Retry in 10s to set PS Drive. Please wait." | Out-File -Append $logpath
Start-Sleep -Seconds 10
New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams
}
# Set the current location to be the site code.
Set-Location "$($SiteCode):\" @initParams
#Add domain user as CM administrative user
"Setting $CMUser as CM administrative user." | Out-File -Append $logpath
New-CMAdministrativeUser -Name $CMUser -RoleName "Full Administrator" -SecurityScopeName "All","All Systems","All Users and User Groups"
"Done" | Out-File -Append $logpath
#Add PS computer account as CM administrative user
$ComputerAccount = $PSComputerAccount.Split('$')[0]
"Setting $ComputerAccount as CM administrative user." | Out-File -Append $logpath
New-CMAdministrativeUser -Name $ComputerAccount -RoleName "Full Administrator" -SecurityScopeName "All","All Systems","All Users and User Groups"
"Done" | Out-File -Append $logpath
$upgradingfailed = $false
$originalbuildnumber = ""
#Wait for SMS_DMP_DOWNLOADER running
$key = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry64)
$subKey = $key.OpenSubKey("SOFTWARE\Microsoft\SMS\Components\SMS_Executive\Threads\SMS_DMP_DOWNLOADER")
$DMPState = $subKey.GetValue("Current State")
while($DMPState -ne "Running")
{
"Current SMS_DMP_DOWNLOADER state is : $DMPState , will try again 30 seconds later..." | Out-File -Append $logpath
Start-Sleep -Seconds 30
$DMPState = $subKey.GetValue("Current State")
}
"Current SMS_DMP_DOWNLOADER state is : $DMPState " | Out-File -Append $logpath
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Trying to enable CAS EnableSCCMManagedCert." | Out-File -Append $logpath
#Configure CAS EnableSCCMManagedCert
$WmiObjectNameSpace = "root\SMS\site_$($SiteCode)"
#Get component
$wmiObject = Get-WmiObject -Namespace $WmiObjectNameSpace -class SMS_SCI_Component -Filter "ComponentName='SMS_SITE_COMPONENT_MANAGER'"| where-object {$_.SiteCode -eq $SiteCode}
#Get embeded property
$props = $wmiObject.Props
$index = 0
foreach($oProp in $props)
{
if($oProp.PropertyName -eq 'IISSSLState')
{
$v = $oProp.Value
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] IISSSLState previous value is $v." | Out-File -Append $logpath
$oProp.Value = '1216'
$props[$index] = $oProp
}
$index++
}
$WmiObject.Props = $props
$wmiObject.Put()
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Set the IISSSLState 1216, you could check it manually" | Out-File -Append $logpath
#get the available update
function getupdate()
{
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Get CM update..." | Out-File -Append $logpath
$CMPSSuppressFastNotUsedCheck = $true
$updatepacklist= Get-CMSiteUpdate -Fast | ?{$_.State -ne 196612}
$getupdateretrycount = 0
while($updatepacklist.Count -eq 0)
{
if($getupdateretrycount -eq 3)
{
break
}
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Not found any updates, retry to invoke update check." | Out-File -Append $logpath
$getupdateretrycount++
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Invoke CM Site update check..." | Out-File -Append $logpath
Invoke-CMSiteUpdateCheck -ErrorAction Ignore
Start-Sleep 120
$updatepacklist= Get-CMSiteUpdate | ?{$_.State -ne 196612}
}
$updatepack=""
if($updatepacklist.Count -eq 0)
{
}
elseif($updatepacklist.Count -eq 1)
{
$updatepack= $updatepacklist
}
else
{
$updatepack= ($updatepacklist | sort -Property fullversion)[-1]
}
return $updatepack
}
#----------------------------------------------------
$state=@{
0 = 'UNKNOWN'
2 = 'ENABLED'
#DMP DOWNLOAD
262145 = 'DOWNLOAD_IN_PROGRESS'
262146 = 'DOWNLOAD_SUCCESS'
327679 = 'DOWNLOAD_FAILED'
#APPLICABILITY
327681 = 'APPLICABILITY_CHECKING'
327682 = 'APPLICABILITY_SUCCESS'
393213 ='APPLICABILITY_HIDE'
393214 = 'APPLICABILITY_NA'
393215 = 'APPLICABILITY_FAILED'
#CONTENT
65537 = 'CONTENT_REPLICATING'
65538 = 'CONTENT_REPLICATION_SUCCESS'
131071 = 'CONTENT_REPLICATION_FAILED'
#PREREQ
131073 = 'PREREQ_IN_PROGRESS'
131074 = 'PREREQ_SUCCESS'
131075 = 'PREREQ_WARNING'
196607 = 'PREREQ_ERROR'
#Apply changes
196609 = 'INSTALL_IN_PROGRESS'
196610 = 'INSTALL_WAITING_SERVICE_WINDOW'
196611 = 'INSTALL_WAITING_PARENT'
196612 = 'INSTALL_SUCCESS'
196613 = 'INSTALL_PENDING_REBOOT'
262143 = 'INSTALL_FAILED'
#CMU SERVICE UPDATEI
196614 = 'INSTALL_CMU_VALIDATING'
196615 = 'INSTALL_CMU_STOPPED'
196616 = 'INSTALL_CMU_INSTALLFILES'
196617 = 'INSTALL_CMU_STARTED'
196618 = 'INSTALL_CMU_SUCCESS'
196619 = 'INSTALL_WAITING_CMU'
262142 = 'INSTALL_CMU_FAILED'
#DETAILED INSTALL STATUS
196620 = 'INSTALL_INSTALLFILES'
196621 = 'INSTALL_UPGRADESITECTRLIMAGE'
196622 = 'INSTALL_CONFIGURESERVICEBROKER'
196623 = 'INSTALL_INSTALLSYSTEM'
196624 = 'INSTALL_CONSOLE'
196625 = 'INSTALL_INSTALLBASESERVICES'
196626 = 'INSTALL_UPDATE_SITES'
196627 = 'INSTALL_SSB_ACTIVATION_ON'
196628 = 'INSTALL_UPGRADEDATABASE'
196629 = 'INSTALL_UPDATEADMINCONSOLE'
}
#----------------------------------------------------
$starttime= Get-Date
$sites= Get-CMSite
if($originalbuildnumber -eq "")
{
if($sites.count -eq 1)
{
$originalbuildnumber = $sites.BuildNumber
}
else
{
$originalbuildnumber = $sites[0].BuildNumber
}
}
#----------------------------------------------------
$retrytimes = 0
$updatepack = getupdate
if($updatepack -ne "")
{
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Update package is " + $updatepack.Name | Out-File -Append $logpath
}
else
{
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] No update package be found." | Out-File -Append $logpath
}
while($updatepack -ne "")
{
if($retrytimes -eq 3)
{
$upgradingfailed = $true
break
}
$updatepack = Get-CMSiteUpdate -Fast -Name $updatepack.Name
while($updatepack.State -eq 327682 -or $updatepack.State -eq 262145 -or $updatepack.State -eq 327679)
{
#package not downloaded
if($updatepack.State -eq 327682)
{
Invoke-CMSiteUpdateDownload -Name $updatepack.Name -Force -WarningAction SilentlyContinue
Start-Sleep 120
$updatepack = Get-CMSiteUpdate -Name $updatepack.Name -Fast
$downloadstarttime = get-date
while($updatepack.State -eq 327682)
{
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Waiting SCCM Upgrade package start to download, sleep 2 min..." | Out-File -Append $logpath
Start-Sleep 120
$updatepack = Get-CMSiteUpdate -Name $updatepack.Name -Fast
$downloadspan = New-TimeSpan -Start $downloadstarttime -End (Get-Date)
if($downloadspan.Hours -ge 1)
{
Restart-Service -DisplayName "SMS_Executive"
Start-Sleep 120
$downloadstarttime = get-date
}
}
}
#waiting package downloaded
$downloadstarttime = get-date
while($updatepack.State -eq 262145)
{
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Waiting SCCM Upgrade package download, sleep 2 min..." | Out-File -Append $logpath
Start-Sleep 120
$updatepack = Get-CMSiteUpdate -Name $updatepack.Name -Fast
$downloadspan = New-TimeSpan -Start $downloadstarttime -End (Get-Date)
if($downloadspan.Hours -ge 1)
{
Restart-Service -DisplayName "SMS_Executive"
Start-Sleep 120
$downloadstarttime = get-date
}
}
#downloading failed
if($updatepack.State -eq 327679)
{
$retrytimes++
Start-Sleep 300
continue
}
}
#trigger prerequisites check after the package downloaded
Invoke-CMSiteUpdatePrerequisiteCheck -Name $updatepack.Name
while($updatepack.State -ne 196607 -and $updatepack.State -ne 131074 -and $updatepack.State -ne 131075)
{
("[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Waiting checking prerequisites complete, current pack " + $updatepack.Name + " state is " + ($state.($updatepack.State)) + ", sleep 2 min...") | Out-File -Append $logpath
Start-Sleep 120
$updatepack = Get-CMSiteUpdate -Fast -Name $updatepack.Name
}
if($updatepack.State -eq 196607)
{
$retrytimes++
Start-Sleep 300
continue
}
#trigger setup after the prerequisites check
Install-CMSiteUpdate -Name $updatepack.Name -SkipPrerequisiteCheck -Force
while($updatepack.State -ne 196607 -and $updatepack.State -ne 262143 -and $updatepack.State -ne 196612)
{
("[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Waiting SCCM Upgrade Complete, current pack " + $updatepack.Name + " state is " + ($state.($updatepack.State)) + ", sleep 2 min...") | Out-File -Append $logpath
Start-Sleep 120
$updatepack = Get-CMSiteUpdate -Fast -Name $updatepack.Name
}
if($updatepack.State -eq 196612)
{
("[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] SCCM Upgrade Complete, current pack " + $updatepack.Name + " state is " + ($state.($updatepack.State)) ) | Out-File -Append $logpath
#we need waiting the copying files finished if there is only one site
$toplevelsite = Get-CMSite |where {$_.ReportingSiteCode -eq ""}
if((Get-CMSite).count -eq 1)
{
$path= Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\SMS\Setup' -Name 'Installation Directory'
$fileversion=(Get-Item ($path+'\cd.latest\SMSSETUP\BIN\X64\setup.exe')).VersionInfo.FileVersion.split('.')[2]
while($fileversion -ne $toplevelsite.BuildNumber)
{
Start-Sleep 120
$fileversion=(Get-Item ($path+'\cd.latest\SMSSETUP\BIN\X64\setup.exe')).VersionInfo.FileVersion.split('.')[2]
}
#Wait for copying files finished
Start-Sleep 600
}
#Get if there are any other updates need to be installed
$updatepack = getupdate
}
if($updatepack.State -eq 196607 -or $updatepack.State -eq 262143 )
{
if($retrytimes -le 3)
{
$upgradingfailed = $true
Start-Sleep 300
continue
}
$retrytimes = $retrytimes + 1
}
}
if($upgradingfailed -eq $true)
{
("[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Upgrade " + $updatepack.Name + " failed") | Out-File -Append $logpath
throw
}
#Set permission
$Acl = Get-Acl $SMSInstallDir
$NewAccessRule = New-Object system.security.accesscontrol.filesystemaccessrule($PSComputerAccount,"FullControl","ContainerInherit,ObjectInherit","None","Allow")
$Acl.SetAccessRule($NewAccessRule)
Set-Acl $SMSInstallDir $Acl
$Configuration.UpgradeSCCM.Status = 'Completed'
$Configuration.UpgradeSCCM.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
$Configuration | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force
Copy-Item $ConfigurationFile -Destination "c:\$LogFolder" -Force
#Waiting for PS ready to use
$Configuration.PSReadyToUse.Status = 'Running'
$Configuration.PSReadyToUse.StartTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
$Configuration | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force
$PSSystemServer = Get-CMSiteSystemServer -SiteCode $PSRole
while(!$PSSystemServer)
{
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Wait for PS finished installing, will try 60 seconds later..." | Out-File -Append $logpath
Start-Sleep -Seconds 60
$PSSystemServer = Get-CMSiteSystemServer -SiteCode $PSRole
}
#Wait for replication ready
$replicationStatus = Get-CMDatabaseReplicationStatus
while($replicationStatus.LinkStatus -ne 2 -or $replicationStatus.Site1ToSite2GlobalState -ne 2 -or $replicationStatus.Site2ToSite1GlobalState -ne 2 -or $replicationStatus.Site2ToSite1SiteState -ne 2 )
{
"[$(Get-Date -format "MM/dd/yyyy HH:mm:ss")] Wait for PS ready for use, will try 60 seconds later..." | Out-File -Append $logpath
Start-Sleep -Seconds 60
$replicationStatus = Get-CMDatabaseReplicationStatus
}
$Configuration.PSReadyToUse.Status = 'Completed'
$Configuration.PSReadyToUse.EndTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
$Configuration | ConvertTo-Json | Out-File -FilePath $ConfigurationFile -Force
Copy-Item $ConfigurationFile -Destination "c:\$LogFolder" -Force