Updated: Microsoft 365 Apps

This is a refresh of my old post Microsoft 365 Apps (Office 365) hantering i MECM (SCCM), or maybe I should write “a refresh of the script”.

In this post, I ensure that the Office Deployment Tool (ODT) is the latest version to support new version/function of Microsoft 365 Apps setup.
I use a modified Powershell script created by Marco Hofmann & Trond Eric Haavarstein to suit my idea.
Original script: https://www.meinekleinefarm.net/download-and-install-latest-office-365-deployment-tool-odt

What this version of the script does:

Download the latest version of the Office Deployment Tool (ODT).
Checks if it’s a newer version of the Office 365 Deployment Tool (ODT), and if it’s a newer version, extracts it to a subfolder with the version number as the folder name. If it is not a newer version, skips this step
Then copies the new setup.exe to both the folder for the source files and the application package in ConfigMgr
And for last it runs the setup.exe (with download xml-file) to download allt the Microsoft 365 Apps

    Download latest Office Deployment Tool (ODT) and Office setup files
    Download latest Office Deployment Tool (ODT), extract setup.exe and download Office setup-files.
    PS:> \\DFSSHARE.ORGANISATION.ORG\...\download.ps1
    Downloads latest officedeploymenttool.exe
    Creates a sub-directory for each new version
    Copies the setup.exe from the sub-directory to source-directory (incl. cmsetup-directory) and download Office setup-files
    Author: Magnus Bäcke
    URL: https://backes.nu
    Original Author: Marco Hofmann and Trond Eric Haavarstein Original Author URL: https://www.meinekleinefarm.net and https://xenappblog.com/ 
    This is the original script: https://www.meinekleinefarm.net/download-and-install-latest-office-365-deployment-tool-odt
$StartDTM = (Get-Date)
$LogDTM = (Get-Date -format "yyyy-MM-dd_HH-mm-ss")
$ODTDownload = "\\DFSSHARE.ORGANISATION.ORG\Office365SetupFiles$\ODTDownload\"              # <-- You need to change the path
$LogPS = "\\DFSSHARE.ORGANISATION.ORG\Office365SetupFiles$\Logs\$LogDTM.log"                # <-- You need to change the path
$SourcePath = "\\DFSSHARE.ORGANISATION.ORG\Office365SetupFiles$\"                           # <-- You need to change the path
$SetupPath = "\\DFSSHARE.ORGANISATION.ORG\CMSourceFiles$\Applications\Microsoft 365\Files\" # <-- You need to change the path
$Downloadxml = 'download.xml'                                                               # <-- You need to change this to the name of your Office download XML-file here, or name your XML-file download.xml
<# No need for any changes below here#>
$DownloadURL = (Invoke-WebRequest -Uri "https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117").Links | Where-Object href -like '*exe' | select -First 1 | select -expand href
$SaveDir = "$ODTDownload\officedeploymenttool.exe"
$ProgressPreference = 'SilentlyContinue'

Set-Location $ODTDownload

Write-Verbose "Setting Arguments" -Verbose
Start-Transcript $LogPS

Write-Verbose "Download latest version of Office Deployment Tool (ODT)." -Verbose

Invoke-WebRequest -Uri $DownloadURL -OutFile $SaveDir

Write-Verbose "Read version number from downloaded file" -Verbose
$Version = (Get-Command .\officedeploymenttool.exe).FileVersionInfo.FileVersion

Write-Verbose "If downloaded ODT file is newer, create new sub-directory." -Verbose
if( -Not (Test-Path -Path $Version ) ) {
    New-Item -ItemType directory -Path $Version
    Write-Verbose "Extract setup.exe from ODT" -Verbose
    .\officedeploymenttool.exe /quiet /extract:.\$Version
    start-sleep -s 5
    Write-Verbose "New folder created $Version" -Verbose
    Set-Location $Version
    Copy-item ".\setup.exe" -Destination $SourcePath -Force
    Write-Verbose "setup-exe copied from $Version to $SourcePath " -Verbose
    Copy-item ".\setup.exe" -Destination $SetupPath -Force
    Write-Verbose "setup-exe copied from $Version to $SetupPath (CM O365 setup Source files)" -Verbose
else {
    Write-Verbose "Version identical. Skipping folder creation." -Verbose

Set-Location $SourcePath
Write-Verbose "Downloading Office setup-files according to the XML-file." -Verbose
Start-Process ".\setup.exe" -ArgumentList "/download $Downloadxml" -Wait -PassThru 

start-sleep -s 15

Write-Verbose "Stop logging" -Verbose
$EndDTM = (Get-Date)
Write-Verbose "Elapsed Time: $(($EndDTM-$StartDTM).TotalSeconds) Seconds" -Verbose
Write-Verbose "Elapsed Time: $(($EndDTM-$StartDTM).TotalMinutes) Minutes" -Verbose

Idéa: Use Task Scheduler to run this late on the second tuesday (or early on the second wednesday) in the month to always have the latest Apps downloaded.

Diskpart to the rescue

In my work, I recently heard that more often new devices (desktop’s/laptop’s) fails in the beginning of the OSD (OS deploy) because of something is wrong with the partitions on the hard drive. The Boot-image can’t download policys or files to the disk, so it fails. Often the IT-person needs to boot the device and re-partition the disk, and after that start the OSD again, and it will work. I have not done some examination on why it fails. The OEM’s OS works on the device/disk. But I have a workaround, or it’s not mine workaround. I did find it on the Internet for a few years ago, so I don’t remember whos to credit (I’m sorry).

But this is the workaround I have.

Begin by creating a txt-file with the content of commands for diskpart we will be using later (this is for UEFI-disks).
sel disk 0 clean convert gpt cre par efi size=200 assign letter=s format quick fs=FAT32 cre par msr size=128 cre par pri assign letter=c format quick fs=NTFS exit
Save the file (I have named my file uefi_disk.txt ), and put it on your SCCM Package-share. Then you will need to create a Package in your SCCM-console, where you will point out the source files (where you saved your new .txt-file). You don’t need to create a program, just select “Do not create a program” and click next, and just go on and finish the wizard. Here is two ways to use this. The first one, if you boot your PC’s from a boot-media (CD/USB), you can create a new boot-media and put in a prestart command to run diskpart. So go one and create a new Task Sequence Media if you choose this way. Mark Boot media, and Next Continue the wizard, entering your “SCCM-info” till you come to Customize the task sequence media. Here you will need to tick the Enable prestart command checkbox, and also enter Command line: cmd.exe /c diskpart /s uefi_disk.txt <– or the name you gave your .txt-file You must also select the Diskpart package you created earlier, and point out your Distribution point. After that, finish the wizard, and you are now ready to boot using your new boot-media.
The other one is to put this in your boot-image (if you PXE-boot your devices, choose this). Using this way the prestart command will always run (when using TS using this boot-image), and you don’t need to create a new boot-image with this prestart command. Go to your Boot-image in the SCCM-console, and right-click it and choose Properties. Go to the Customization tab, and tick the Enable prestart command checkbox, and also enter Command line: cmd.exe /c diskpart /s uefi_disk.txt <– or the name you gave your .txt-file Klick Ok, to save and re-distribute your boot-image, and after that your done.
When you are here, click Next And diskpart will run After diskpart is finished, you can choose your TS, and continue your installation

Windows Defender Scheduled Scans Drains Laptop Battery

I recently received a question whether it is possible to set Windows Defender to stop a scheduled scan on a laptop that was on AC power when the scheduled scan started, but later switchs to run on battery (we dont want to drain the battery).
I have Googled like crazy for days, but my googlefu has not been sufficient. I have looked through group policy’s again and again, but no, I can not find the solution.
I have also not seen any such setting in ConfigMgr 1602 that we use at work.

But just now, it hit me. Why not look in the Task Scheduler?
Said and done, and 10 seconds later, the question was resolved.

 Open the Task Scheduler.
 Expand Task Scheduler Library (by clicking on the arrow in front of Task Scheduler Library).
 Expand Microsoft.
 Expand Windows.
 Go down to, and click on Windows Defender.
 Right click on Windows Defender Scheduled Scan, and select Properties.
 Go to the Conditions tab.
 Check the box infront of Stop if the computer switches to battery power.
 Click Ok, and thats it.



Ta bort, eller blockera Appar i Windows 10?

Under tiden jag har labbat med Windows 10 för att kunna skapa en sådan perfekt installations-avbild som möjligt så upptäckte jag att ta bort appar, så som Windows Store, OneDrive, etc inte genererar det bästa resultatet. För hux flux så kan företagets policy ändras och tillåta den borttagna appen. Nej, modifiera Windows så lite som möjligt är det bästa.
Så blockera då?
Ja, det är rätt väg. För det man blockerar kan man oblockera ta bort blockeringen för.

Av Jörgen Nilsson, ccmexec.com kan man lära sig mycket (har en otrolig mängd bokmärken i Chrome från hans blogg).Till exempel hans bloggpost “Blocking built-in apps in Windows 10 using Applocker“. Fungerar jättebra, om man använder Applocker. För den som vill helt radera appar från Windows 10 rekommenderar jag denna bloggpost; Removing built-in Apps from Windows 10 using Powershell.
På företaget jag jobbar på har vi inte använt oss utav Applocker tidigare, och när jag ny följde Jörgens utmärkta tips så blev resultatet först lyckat. Men sedan så hände något, “random” program startade inte, den var blockerad att köras. Jag dubbelkollade, trippelkollade, fyrlingkollade och jämförde inställningar. Det fanns bara en lösning för oss, att ta bort inställningarna jag gjorde i Applocker.
Visst, jag kunde ha fortsätt att “felsöka”. Men tiden att lägga på det och det vi vill blockera gick inte ihop.

Så om man inte vill radera Windows Store eller OneDrive, och man inte kan/vill använda Applocker så går det ju alldeles utmärkt att blockera dessa via GPO i alla fall.

Så här löste jag det (vi vill blockera Windows Store och OneDrive):

  • Först så skapade jag en helt ny GPO, satt ett WMI-filter* på den för att säkerställa att den endast slår mot Windows 10 maskiner.
  • Sedan öppnade jag upp “Windows 10 Policy v1.0 och klickade mig fram till:
    Computer Configuration > Policies > Administrative Templates > Windows Components
  • Väl där, valde jag OneDrive och under där högerklickade jag på Prevent the usage of OneDrive for file storage och valde Edit.
  • Markera Enabled och klicka på Ok- knappen
  • Sedan gick jag nedåt i trädet under Computer Configuration > Policies > Administrative Templates > Windows Components till jag kom till Store
  • Kort och gott, under Store markerade jag Turn off the Store application och valde Edit
  • Markera Enabled och klicka på Ok- knappen

Så var det fixat. Windows Store och OneDrive är blockerade. När företaget ändrar sig, så tar det bara någon minut att oblockera ta bort blockeringen för dessa.

Och när man väl börjar kika på vilka inställningar man kan göra via GPO, så behöver man inte lägga jätte mycket tid på att skapa en egen installations-avbildning.


*WMI-filter för Windows 10:
Namespace: root\CIMv2
Query: select * from Win32_OperatingSystem where Version like ”10.0%” and ProductType=”1″

Uppdatera Configmgr Content, där det behövs

Återigen, Rikard Rönnkvist spar mig massor av tid med sina PowerShell-script, tack!

    $sccmServer = "configmgr.snowland.se",
    $sccmSiteCode = "ABC",
    $failStates = "2, 3, 5, 6", # Retrying and Failed (Both Install and Removal)
    $packageTypes = "0, 3, 4, 8, 257, 258" # Not checking 5 (SUP) due to automatic deployments
Write-Host "Searching for failed content distributions"
ForEach ($FailedDist in (Get-WmiObject -ComputerName $sccmServer -Namespace "ROOT\SMS\Site_$($sccmSiteCode)" -Query "SELECT * FROM SMS_PackageStatusDistPointsSummarizer WHERE State IN ($($failStates)) AND PackageType IN ($($packageTypes))" | Sort-Object PackageID)) {
    # Figure out servername from NalPath
    $failedServer = $FailedDist.ServerNALPath.Substring($FailedDist.ServerNALPath.LastIndexOf("]")+3).Trim("\")
    # Get the distribution points that content wouldn't distribute to
    ForEach ($FailedDPDist in (Get-WmiObject -ComputerName $sccmServer -Namespace "ROOT\SMS\Site_$($sccmSiteCode)" -Query "SELECT * FROM SMS_DistributionPoint WHERE SiteCode='$($FailedDist.SiteCode)' AND PackageID='$($FailedDist.PackageID)' AND ServerNALPath LIKE '%$($failedServer)%'") ) {
        # Refresh content on the selected DP
        Write-Host "Refreshing $($FailedDPDist.PackageID), type $($FailedDist.PackageType) in state $($FailedDist.State) on $($failedServer)"
        $FailedDPDist.RefreshNow = $true
        $FailedDPDist.Put() | Out-Null
Write-Host "Done!"

Tack till Rikard Rönnkvist, källa: SnowLand