Home Cireson Uploads

IT Monkey will place code here as examples of what Cireson's consulting team has to offer as well as examples for public consumption to benefit the Microsoft System Center community as a whole.


All files and projects located here come as is and without any warranty or support. We will attempt to improve the projects as time goes on based on customer and community demand. Comments and improvements are welcome as well as customization requests. Your use of these Cireson Uploads is subject to our Terms of Use.

Cireson's support team has no information on these projects outside of what you have available and will not provide support for these enhancements, extensions, and scripts.

Dont forget to checkout solutions uploaded by our customers, partners and community members here.

Example: Cireson SCSM Portal on Docker Windows Containers

Joe_BurrowsJoe_Burrows Cireson Devops Super IT Monkey ✭✭✭✭✭
edited May 2018 in Cireson Uploads

Seem all the cool peps are running Applications in containers these days, and considering I haven’t posted in a while - I thought I’d share a working example to quickly create instances of the Cireson Portal for your dev, test environments to help you be one of those cool peps  B) .

Publish the different versions to your container repo to give you the ability to freely move the portal around your various environments to automate the deployment, recovery or scaling of the portal quickly.

Overview Steps:

  1. Creating the Docker Host
  2. Creating the GSMA Account, Credspec file and Permissions
  3. Building the Portal Docker Image
  4. Running the Image
Step 1: Creating the docker host

On a Windows 2016 server, Start up a PowerShell command window running as an administrator and run the following commands to download and install the latest version of Docker:

<p>Install-Module&nbsp;DockerMsftProvider&nbsp;-Force </p><p><br></p><p>Install-Package&nbsp;Docker&nbsp;-ProviderName&nbsp;DockerMsftProvider&nbsp;-Force</p>

Step 2: Permissions

As docker does not yet have active directory support, we must configure a few things in AD and the docker host to have the portal permissions working happily as they would with a domain joined server. Using Group Managed Service Accounts on the host any service running on the nested container as LocalSystem can act as the the gMSA account as their domain indentity: (see https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts for more information)

-PrincipalsAllowedToRetrieveManagedPassword 'Domain Computers'

  • Import AD Modules & Install the gMSA Account on the Docker Host

<p>Add-WindowsFeature </p><p>
RSAT-AD-PowerShell </p><p>
Import-Module ActiveDirectory </p><p><br></p><p>Install-AdServiceAccount GMSA_DOCKER </p><p><br></p><p>Test-AdServiceAccount GMSA_DOCKER</p>

New-CredentialSpec -Name GMSA_DOCKER -AccountName GMSA_DOCKER

  • .Add GMSA_Docker to your SCSM Administrators group for SCSM, and grant GMSA_DOCKER$ permissions in SQL Server to ServiceManager & ServiceManagement (Or if creating a new portal database - grant sysadmin rights)


  • Options
    Joe_BurrowsJoe_Burrows Cireson Devops Super IT Monkey ✭✭✭✭✭
    edited April 2018
    Step 3: Portal Docker Build

    If you not familiar with docker, I’d recommend following the examples on the docker website here.

    First we need to automate everything the portal needs in order to get built, which we declare in a dockerfile. Luckily the Cireson Portal comes already scripted in PowerShell for all the pre-reqs and install - so the only changes we need to make to the install process is to have the AppPool, CacheBuilder and Platform cache run as LocalSystem so the container can impersonate the gMSA account that has the correct SQL and Service Manager permissions.

    We will need the following on a new container to complete a build with the Cireson Portal

    1. A Local Admin Account that we can set for the parameters installportal.ps1 requires for services.
    2. Some folders on the image to hold the packages and scripts we want locally
    3. Cireson Portal for SCSM Zip package downloadable from downloads.cireson.com
    4. Some Powershell scripts to switch the Service Accounts to LocalSystem
    5. Other bits and bobs

    Bring this all together in a dockerfile – too easy right? Will break about the dockerfile with what each step is doing (The complete dockerfile used in this example can be downloaded from the post above and adjusted to suit your environment).

    <p># escape=` </p><p><br></p><p>FROM microsoft/dotnet-framework:3.5 </p><p><br></p><p>LABEL maintainer "Joe Burrows" </p><p><br></p><p># Container Parameters </p><p><br></p><p>ARG smp_setup_zip_uri=https://ciresonreleases.blob.core.windows.net/servicemgrportal/PreviousVersions/ </p><p><br></p><p>ARG ManagementDBName=ServiceManagement </p><p><br></p><p>ENV ManagementDBName ${ManagementDBName} </p><p><br></p><p>ENV smp_setup_zip_uri ${smp_setup_zip_uri} </p><p> </p><p>SHELL ["powershell","-Command"]</p>

    By default the escape character in Docker is \ - this becomes a pain when working with Windows containers so is changeable by declaring # escape=` at the beginning.

    The image we are using as the base is the Official Microsoft Server Core Image for docker with dotnet-framework 3.5

    Then we set ARG which are the augments we can use when running a docker build (more on this latter), we are setting a default in case nothing is declared in the docker build command – and then storing them as environment variables that can called in the scripts in the steps latter in the docker file.

    Next we create our Local Admin User using the net user command and net localgroup with a super secure password

    <p># Container Image Environment Configuration </p><p>##Create Local Admin User </p><p><br></p><p>RUN NET USER ContainerAdmin P@ssw0rd /add /y /expires:never; `</p><p>NET LOCALGROUP Administrators ContainerAdmin /add</p>

    Next we want create our working folders, download the portal installer ZIP to our image from our Environment Variable we stored above, download our custom scripts, unblock the zip, unzip, run the installpreqs and remove that annoying Default IIS Web Site.

    <p># Download SMP Setup Zip, Container
    Scripts and Install Pre-reqs </p><p><br></p><p>EXPOSE 80  </p><p>  </p><p><br></p><p> RUN md C:\Setup; `</p><p>&nbsp;&nbsp;&nbsp;
    md C:\Scripts; `</p><p>&nbsp;&nbsp;&nbsp;
    Write-host "Downloading SMP From $ENV:smp_setup_zip_uri...."; `</p><p>&nbsp;&nbsp;&nbsp;
    invoke-WebRequest -outfile C:\Setup\SMP.Zip $ENV:smp_setup_zip_uri; `</p><p>&nbsp;&nbsp;&nbsp;
    Write-host "Downloading Scripts From https://ciresonresources.blob.core.windows.net/docker/EvalLab/smp.....";`</p><p>&nbsp;&nbsp;&nbsp;
    invoke-WebRequest -outfile C:\Scripts\Update-Service.ps1 https://ciresonresources.blob.core.windows.net/docker/EvalLab/smp/Update-Service.ps1;`</p><p>&nbsp;&nbsp;&nbsp;
    invoke-WebRequest -outfile C:\Scripts\Run-Database-Dac.ps1 https://ciresonresources.blob.core.windows.net/docker/EvalLab/smp/Run-Database-Dac.ps1;`</p><p>&nbsp;&nbsp;&nbsp;
    unblock-file -path C:\Setup\SMP.Zip; `</p><p>&nbsp;&nbsp;
    Expand-Archive C:\Setup\SMP.Zip C:\Setup; `</p><p>.\Setup\InstallPreReq.ps1; `</p><p>Remove-Website -Name 'Default Web Site'</p>

    Before we run the InstallPortal.PS1 script we need to edit the script so it installs the App Pool to Run as LocalSystem (Rather than a Windows AD User), this is achieved by finding and replacing some lines in the script as below:

    <p>## Replace AppPool Account Settings in Installer script to Use LocalSystem</p><p>
    </p><p>RUN</p><p>((Get-Content "C:\Setup\InstallPortal.ps1")-creplace 'appPool.processModel.identityType = 3','appPool.processModel.identityType = 2') | Set-Content "C:\Setup\InstallPortal.ps1"</p>

    Then we are good to declare the parameters the InstallPortal script requires for installation:

    & {C:\Setup\InstallPortal.ps1 ` </p><p><br></p><p>-ManagementServer 'EvalLab-SCSM.evallab.local' ` </p><p><br></p><p>-SQLServer 'EvalLab-SQL.evallab.local' ` </p><p><br></p><p>-PortalUser '.\ContainerAdmin' ` </p><p><br></p><p>-SiteRootPath 'C:\InetPub\' ` </p><p><br></p><p>-PortalPassword 'P@ssw0rd' ` </p><p><br></p><p>-CreateManagementDB $true ` </p><p><br></p><p>-ManagementDBName $ENV:ManagementDBName ` </p><p><br></p><p>-ExecuteDac $true ` </p><p><br></p><p>-InstallManagementPacks $true ` </p><p><br></p><p>-ApplicationTitle 'Cireson Eval Lab Portal' ` </p><p><br></p><p>-InstallWebsite $true ` </p><p><br></p><p>-ManagementServerBinaryPath '\\EvalLab-SCSM.evallab.local\c$\Program Files\Microsoft System Center\Service Manager\SDK Binaries' ` </p><p><br></p><p>-RunCacheBuilderAsService $true ` </p><p><br></p><p>-CacheServiceUserName '.\ContainerAdmin' ` </p><p><br></p><p>-CacheServicePassword 'P@ssw0rd' ` </p><p><br></p><p>-AnalystsADGroup 'SCSM Analysts' ` </p><p><br></p><p>-AssetManagementADGroup 'SCSM Asset Managers' ` </p><p><br></p><p>-KnowledgeManagerADGroup 'SCSM KB Managers' ` </p><p><br></p><p>-SMSQLServer 'EvalLab-SQL.evallab.local' ` </p><p><br></p><p>-SMTPServerName 'EvalLab-SCSM.evallab.local' ` </p><p><br></p><p>-SMTPServerPort 25 ` </p><p><br></p><p>-SMTPEmailReturnAddress 'Cireson@EvalLab.Local' ` </p><p><br></p><p>-AnalyticServiceUserName '.\ContainerAdmin' ` </p><p><br></p><p>-AnalyticServicePassword 'P@ssw0rd'` </p><p><br></p><p>-InstallAnalytic $true ` </p><p><br></p><p>-AnalyticFrequencyStartDate '2017-12-09T16:17:43.747224+00:00' ` </p><p><br></p><p>}; `</p>

    Next we want to run our custom script that we downloaded to the image to switch the installed services from our local user to LocalSystem

    <p>& \Scripts\Update-Service.ps1 "CacheBuilder"; ` </p><p>
    </p><p>& \Scripts\Update-Service.ps1 "Platform_Cache"</p>

    And also Delete the customspace folder (As we want to bind the customspace folder from the dockerhost to the container – to make customization easier and if we delete containers we don’t want to lose customizations)

    <p>#Empty CustomSpace Folder so it can be mapped as a Volume from the docker Host in the docker run command</p><p>
    </p><p>RUN Remove-item C:\InetPub\CiresonPortal\CustomSpace -Recurse -Force -verbose</p>

    The last step is optional but I create a scheduled task to re-run the DAC file on container startup incase the image was pulled from another environment I want to make sure the database gets upgraded correctly.

    <p>#Create Scheduled task to run DAC On container start to Upgrade database incase image pulled from Repo rather than built locally</p><p>
    </p><p>RUN schtasks /Create /TN Run-Database-Dac /SC ONSTART /TR 'c:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe C:\Scripts\Run-Database-Dac.ps1' /ru SYSTEM</p>

    With all the above in a file called ‘dockerfile’ we can then run docker build to create an image with all the above steps run. Set our build arg to the installer zip we want in the below example we using We do need to set –security-opt to tell docker to run as GMSA_Docker:

    <p>$SMPVersion = "",&nbsp;&nbsp; </p><p><br></p><p>$SMPZipURL = "https://ciresonreleases.blob.core.windows.net/servicemgrportal/PreviousVersions/$SMPVersion.zip"</p><p> </p><p>Docker build -t portal:$SMPVersion --security-opt "credentialspec=file://GMSA_Docker.json" --build-arg smp_setup_zip_uri=$SMPZipURL .</p>

    Now we successfully have saved into an image we can quickly run or share across multiple environments :D

    docker images will show the newly created image with the tag:

  • Options
    Joe_BurrowsJoe_Burrows Cireson Devops Super IT Monkey ✭✭✭✭✭
    edited April 2018
    Step 4: Running the Image

    Now we have the image we want to run the image using docker run and setting the needed switches:

    • -dit to run detached
    • -p port bindings (in this case mapping port 80 on the host to port 80 on the nested container - recommend creating a transparent network so you dont have to nat ports to the containerhost, once the network is created you can simply assign an IP address per container replace -p with --network={NameOfYourTransparentNetwork} --ip={IPAddressToAssignContainer} and the EXPOSE ports declared in the docker file will be accessible on that IP address)
    • –dns IP address of the DNS server in the vnet so the container can do internal name resolution
    • -v to bin a folder on the host to a folder on the windows container (In this case custom space so anything in C:\Container-Volumes\SMP\CustomSpace will be available to the portal in the container)
    • –name container name – optional but I like to have the container named after the application its running rather than the random names the docker daemon assigns.
    • -h Windows Container Host name – must match the name of the GMSA account its impersonating.
    • Credentialspec (as created from the powershell script in the permissions step)
    • Docker Image name to run

    docker run -dit -p 80:80 --dns= -v C:\Container-Volumes\SMP\CustomSpace:C:\Inetpub\CiresonPortal\CustomSpace --dns-search=evallab.local --name=SMP-Portal -h GMSA_Docker --security-opt "credentialspec=file://GMSA_Docker.json" portal:


  • Options
    Discussion has been moved to the below thread and contains further examples on containerizing the portal with docker-compose:

This discussion has been closed.