Quantcast
Channel: Operating System Deployment – blog.hosebei.ch
Viewing all 19 articles
Browse latest View live

SCCM 2012 R2 – Remove Client from Collection after OSD 1.1

$
0
0

Hey, here is Martin again.

One of the most viewed article on this blog is about this Topic. I will give a small update for the new System Center 2012 Configuration Manager R2 release. Thus this release now supports to run most of the cmdlets for SCCM also in x64 mode (exceptions see: http://technet.microsoft.com/library/dn236347.aspx).
And with this, the script needs no changes, except the remove of the check for the x86 architecture.
I just added a check that the collection has to exist, before the check is done, that the Direct Membership rule exist for the specific device in the specific collection.

Please read my last blog post about this Topic carefully (http://blog.hosebei.ch/2013/05/20/sccm-2012-sp1-remove-client-from-collection-after-osd/), as a small reminder:
-Trust the Module that has to be imported
-The server that runs the rule has to be added with permissions

The comments can be also very useful for you when you got Problems with the implementation!

Here you can find my updated script:

For any suggestions what I could make better, I’m happy to hear from you something in the comments :)



SCCM 2012 R2 – Speed up and slow down reboot in one step!

$
0
0

What do I want to say with this sentence, because for the first sight, it makes not a lot sense, but if we looking deeper…
With System Center 2012 Configuration Manager R2 the Task Sequences got a new step called “Set Dynamic Variables”. With this, you can set variables a lot easier than before, and you can set multiple TS variables in one step.
I would like to use two useful TS variables for OSD to explain this new step in the Task Sequence.
The first variable is “SMSTSErrorDialogTimeout” (referring to http://technet.microsoft.com/en-us/library/bb632442.aspx), this variable let you define, how long the error dialog is shown, before the System reboot is initiated, and you might lose your smsts.log. The value has to be in seconds, and the Default value is 15 minutes, usually an hour is a value I use. But this Settings should only be active when my custom TS variable OSD-DevMode is existing, to achieve this, simply click on add Rule and then Task Sequence Variable:
TSVariables02
The upcoming wizard is filled up and accepted by clicking on OK:
TSVariables03
The TS step will then be updated with your rule:
TS OSD variable step rule
Now it is time to add our TS variable, click on Add Variables and Existing variables:
Add existing variable
In the following window you can select the right one from known variables:
Add smstserrordialog variable
The variable is then added to the list, and by a click on the line, you can edit the value, which I set to 3600:
Set value
Now I will set the second variable, this is the SMSTSRebootDelay, it controls how long the Dialog is shown, when a System initiated reboot is pending. Usually you don’t need to see this message. The Default value is 30 seconds, and I will set it to 0, this means no Dialog is shown. You can repeat the steps from above, expect to create a rule:
TSVariables08
So this will set the second variable even when the TS Variable OSD-DevMode is not present. I highlighted the Move Up and Move Down buttons to show, even, if you created a rule or variable setting in the wrong order, you can change it afterwards, no need to copy/paste like in the options.

Have fun with faster and even slower reboots :)
Martin


SCCM 2012 R2 – BYOD with Windows To Go and Bitlocker in Enterprise

$
0
0

Hi there, here’s Martin again.

My last Blog Post was about to create a Windows 8.1 To Go deployment with System Center 2012 Configuration Manager R2, and which configurations are required or are nice to set. In this Blog post, I tell you about how I expand the Task Sequence with enabling Bitlocker for the Windows ToGo and how to set a computername.

First, this process is also described on TechNet: http://technet.microsoft.com/en-us/library/jj651035.aspx
Note that the Task Sequence Variable “OSDBitLockerPIN” has to be set.

Your first step in the process of enabling Bitlocker for Windows To Go depends, on where would you like to save the recovery Password. I would suggest you to save them in Active Directory. For all questions about Bitlocker and recovery Password, please refer to the appropriate TechNet articles depending on your needs.

You have then to create a package, which includes the Windows To Go Bitlocker tool for enabling the encryption. Navigate to the following folder below your SCCM Installation Directory:
$InstallDirectoryOSDToolsWTGBitLocker
Copy the entire Content to your package Location and create a new package. When creating the Bitlocker ToGo package, there is no need to create a program, do not forget to distribute the package on a Distribution Point!
When this is done, open your Task Sequence and add a “Run Command Line” step to your Task Sequence:
BitlockerToGo01
In the example of the TechNet article, the x86 Version of the program is used. My Windows 8.1 is a x64 Version, so my command line ist:
x64osdbitlocker_wtg.exe /Enable /pwd:AD
The switch /pwd:AD does requires the process to store the bitlocker recovery key to Active Directory. As package, choose your bitlocker Togo package, which you have created before.
Important: Set the following Option, that this step will only be run in a Windows To Go Environment:
Task Sequence Variable “_SMSTSWTG” equals “True”:
Run command Line Step option

Your Task Sequence is done, you could create your prestage media. But wait, think about how to set your variable OSDBitLockerPIN, which is necessary to enable Bitlocker To Go! This Pin Code has to be 8 digit long for minimum and 64 digit in maximum. If characters are allowed depends on your Group Policy Setting, the option enhanced Pin Codes is to check.
While on testing, I added this variable hardcoded to the variable while creating the prestage media as defined variable. But since I already added this simple script for prestart command to get a TS start delay and set an appropriate computername:
wscript.sleep(45000)
strComputerName = InputBox("Enter computername")
Set env = CreateObject("Microsoft.SMS.TSEnvironment")
env("OSDComputerName") = strComputerName

I added some lines to also ask for the bitlocker key. I also added a check, if the Computer Name is valid, and if the bitlocker pin code is valid. A missing Point is the check against the Active Directory, because if you choose a computername which is already in use, the TS will overwrite this one. You will find the script copy /pasted at the end of the blog post, and also under this link: https://skydrive.live.com/redir?resid=65440BAA507106AD%21700

The Script has 3 variables, that are to set by you:
iBootDelay = 45 'Time in second the TS waits before start, important to get network up and running
bBitLockerEnabled = "True" 'If set to True, script will ask for BitlockerPin
vTSDeploymentID = "S01000C4" 'Has to be set to your deployment on the unkown computer collection

Self-explanatory I hope :)

For the script, just create a new package or use an existing, and then add the package with the script to the prestart command wizard:
Script Usage

If there are enough comments for AD integrated computername check, I will update the Script and blogpost.
Any other suggestions to the script and other ideas are warmly welcome.

Two ideas I already got is:
-User Primary device
-Language Selection

But as stated above, only when some People are asking for it.

————–Script————–
' Region Description
'
' Name: prestage1.0.vbs
' Author: martin wüthrich
' Version: 1.0
' Description: Used for Windows ToGo deployments
'
'
' EndRegion

Option Explicit

Dim iBootDelay
Dim bComputerNameOK, bBitLockerEnabled
Dim vComputername, vTSDeploymentID
Dim oTSenvironment

'User defined variables
iBootDelay = 45 'Time in second the TS waits before start, important to get network up and running
bBitLockerEnabled = "True" 'If set to True, script will ask for BitlockerPin
vTSDeploymentID = "S01000C4" 'Has to be set to your deployment on the unkown computer collection

'------------------------------------
'Main Script

'Sleep before start
WScript.sleep(iBootDelay * 1000)

'Set Task Sequence environment object
Set oTSenvironment = CreateObject("Microsoft.SMS.TSEnvironment")
'Set TS Deployment ID
oTSenvironment("SMSTSPreferredAdvertID") = vTSDeploymentID

'------------------------------------
'ask For computername
Do While bComputerNameOK "OK"
vComputername = InputBox("Enter computername (allowed chars [Aa-Zz], [0-9]; max 14 chars)")
bComputerNameOK = fCheckComputername(vComputername)

'Check Against AD
'probably in future release... :)

Loop
'Set TS Variable
oTSenvironment("OSDComputerName") = vComputername

'------------------------------------
'Ask For Bitlocker Pin Code
If bBitLockerEnabled = "True" Then
Dim vBitlockerCode
Dim bBitlockerCode
Do While bBitlockerCode "OK"
vBitlockerCode = InputBox("Enter BitlockerPin ((allowed chars [0-9]; min 8 chars max 64 chars)")
bBitlockerCode = fBitlockerCode(vBitlockerCode)

Loop
'Set TS Variable
oTSenvironment("OSDBitLockerPIN") = vBitlockerCode

End If

'Functions
Function fCheckComputername(vComputernameCheck)
Dim iCheckNumber, sChar
fCheckComputername = "OK"

For iCheckNumber = 1 To Len(vComputernameCheck)
sChar = Mid(vComputernameCheck,iCheckNumber,1)
If (Asc(sChar) > 96 And Asc(sChar) 47 And Asc(sChar) 14 Then
fCheckComputername = "NotOK"
End If

End Function

Function fBitlockerCode(vPinCodeCheck)

Dim iCheckNumber, sChar
fBitlockerCode = "OK"

For iCheckNumber = 1 To Len(vPinCodeCheck)
sChar = Mid(vPinCodeCheck,iCheckNumber,1)
If sChar = 0 Or sChar = 1 Or sChar = 2 Or sChar = 3 Or sChar = 4 Or sChar = 5 Or sChar = 6 Or sChar = 7 Or sChar = 8 Or sChar = 9 Then
' Do nothing with Chars [0-9]
Else
fBitlockerCode = "NotOK"
Exit For
End If
Next

If Len(vPinCodeCheck) >= 8 And Len(vPinCodeCheck) <= 64 Then
'Pin is OK
Else
fBitlockerCode = "NotOK"

End If

End Function


SCCM 2012 R2 – OSD Error 0x87d00267

$
0
0

Hi, here’s Martin again.
Well, as written in a recent Blog Post (http://blog.hosebei.ch/2013/11/21/sccm-2012-install-windows-7-on-ssd-fails-with-error-0x87d00267/), I was thinking of, that the Problem should be resolved, but we had still the same issues.
Cause of we had nailed down the Problem to the Network, someone came up with the idea to set the Network Speed of the NIC instead of using auto configuration.
When searching for the method to set the Network Card to 100Mbit Full Duplex this by command line we ended up on this excellent blog on TechNet:
http://blogs.technet.com/b/networking/archive/2009/01/08/configuring-advanced-network-card-settings-in-windows-server-2008-server-core.aspx
So we wanted to set this Key (“*SpeedDuplex”) while on OSD to 4, as it means that the Network Card will set up the Network Connection with 100Mbit/s FullDuplex. The Import of Registry Keys might not be a good Option, because the IDs can Change, as far as I know. So I wrote a small powershell script to Change the value, you can download it here:

and you will find the code also here:
# Description: This script set the NIC speed from automatic to 100 Full Duplex
# Usage: powershell.exe -executionpolicy bypass -file "Set_NIC_Speed.ps1 -NicSpeed Auto/100MB"
# Author: Martin Wüthrich, itnetx gmbh
#
#Exit Codes:
#1: No startup parameters defined
#2: Wrong startup parameter. Only Auto and 100MB allowed

#-----------------------------
#Check Input Param
#-----------------------------
Param($NicSpeed)
If($NicSpeed) {}
Else {
Write-Host "You have to define the new NIC-Speed with a startup parameter Auto or 100MB."
exit 1
}

#Set NIC Speed Value
If($NicSpeed -eq "100MB") {
$NICSpeedValue = 4
$NICSpeedValueOld = 0
}
ElseIf($NicSpeed -eq "Auto") {
$NICSpeedValue = 0
$NICSpeedValueOld = 4
}
Else {
Write-Host "Wrong parameter omitted! Auto or 100MB are available values."
Exit 2
}

$GetNICKey = Get-Item -Path HKLM:SYSTEMCurrentControlSetControlClass"{4d36e972-e325-11ce-bfc1-08002be10318}"

ForEach($SubKey in $GetNICKey.GetSubKeyNames()){
If($SubKey -eq "Properties"){
#Do nothing, because no access to this key
}
Else {
$Nic = Get-Item -Path ($GetNICKey.PSPath + "" + $SubKey)
If ($Nic.GetValue("*SpeedDuplex") -eq $NICSpeedValueOld) {
#Write-Host $Nic.Name
Set-ItemProperty -Path $Nic.PSPath -Name "*SpeedDuplex" -Value $NICSpeedValue

}
}
}
We are still seeking for the issue of this Problem, and we use this script as a Workaround. But as so far, we can stage now our Computers with SSD again.

If you ask yourself, why I didn’t use a VBScript, just because VBS will be more and more unusable for Scripting. Change now to powershell, or learn “Would you like to get fries to that” ;)
Hope this helps.


SCCM 2012 R2 – Include Client Hotfix or Cumulative Update while on OSD

$
0
0

Refer to this Blog post, I decided to create a new one about including Hotfixes in OSD. Specially the new Release of SCCM 2012 R2 brings an annoying issue with extremly slow Downloads while on OSD (http://support.microsoft.com/kb/2910552 ; this Hotfix superseding the KB2905002 which was first used in this blog).

There are two nice ways, how to apply Hotfixes like this to the Client while on OSD, one is documented and thus supported, the other one does just work :)
The one that works, but neither documented or supported, is quite simple and already explained in this blogpost (http://www.m4ttmcg.com/2013/05/sccm-2012-client-push-including.html). Just create the folders:
C:\Program Files\Microsoft Configuration Manager\Client\x64\ClientPatch
C:\Program Files\Microsoft Configuration Manager\Client\i386\ClientPatch

and copy the appropriate architecture from your hotfix to one of this Folder. Do not Forget to update your Client Package to be sure using the Files with the Hotfixes.

The other way is to create a package, and copy the files with a package to the Client. First. create a package Location for the hotfix files and create two Folders named AMD64 and X86:
Create Package location

Now navigate to the hotfix Folder and open the Client Folder:
C:\Program Files\Microsoft Configuration Manager\hotfix\KB2910552\Client
Copy the appropriate architecture to the Package Folder, mind to delete the architecture from the file Name:
"\\servershare\Deployment\Packages\Microsoft\SCCM Client\2012 R2\CU0\AMD64\configmgr2012ac-r2-kb2910552.msp"
"\\servershare\Deployment\Packages\Microsoft\SCCM Client\2012 R2\CU0\X86\configmgr2012ac-r2-kb2910552.msp"

As example, the x64 Folder:
Patch package

Now it is time to create the package, well, it’s that easy with this powershell command:
New-CMPackage -Name "SCCM Client 2012 R2 CU0" -Language "MUI" -Manufacturer "Microsoft" -Path "$PATH_TO_YOUR_PACKAGE" -Version "2012 R2 CU0"
And we don’t need to create a program, because we only use this package within our Task Sequence, but don’t forget Distribute the Package to your Distribution Points.

Make sure, that you set a Variable when formatting your System Drive, on BIOS an UEFI:
Set Disk VariableThen use this variable also to deploy Windows on the correct Drive: Apply Operating System
Now create a simple “Run Command Line” step in your Task Sequence, right before the step “Setup Windows and Configuration Manager” where you copy the file to a Folder on the System Drive. This Folder and the Content will remain after the Installation, so you have to delete them with another step, or leave it in the temp Directory. Here is my step:
cmd.exe /c xcopy %PROCESSOR_ARCHITECTURE%*.* %OSD_System%windows\temp\SCCMHotfix /E /H /C /I /Q /Y
OSD TS Step 01

Now, the last step, add the Patch to the SCCM Agent Installation, this is my Installation properties::
SMSCACHEFLAGS=PERCENTDISKSPACE;NTFSONLY SMSCACHESIZE=10 SMSMP=$FQDN_MP FSP=$FQDN_FSP PATCH=C:\windows\temp\SCCMHotfix\configmgr2012ac-r2-kb2910552.msp
Installation properties

If this is not working, you named the subdirectories wrong in your package, or you forgot to remove the architecture from the files.
Hope this helps, Martin


SCCM 2012 – Display special lock Screen when OSD was unsuccessful

$
0
0

Hi, here’s Martin again with a blog about how to Display a Special Lock Screen, when the Operating System Deployment Task Sequence Fails. When you are using System Center 2012 Configuration Manager, you might want to have an easy solution to see, if a OSD was successful or not. Normally you see this Picture after a Windows 8.1 OSD:
Windows 8.1 Normal Lock Screen

So even if there are better and more robust Solutions through Status Message rules, sometimes you would like just to get a visible check. In this blog, I’ll Show you an easy way to achieve this.

The following steps has to be taken:
1. Create a failure Picture
2. Copy the Scripts to the Package Location
3. Create the Package
4. Add the Steps to the Task Sequence

1. Create a failure Picture
This is easily done through paint:
Paint Picture
Safe the Picture as jpg with the Name “OSD_Failed.jpg” in the designated Package Directory.

2. Copy the Scripts to the Package Location
Know create at the Package Location two files, the first one is named SetFailed_Background.bat which will set the failed LockScreen. The Content of this Batch is:
takeown /f C:\Windows\Web\Screen
takeown /f C:\Windows\Web\Screenimg100.jpg
icacls C:\Windows\Web\Screen /grant:r *S-1-5-32-544:F
icacls C:\Windows\Web\Screen\img100.jpg /grant:r *S-1-5-32-544:F
copy C:\Windows\Web\Screen\img100.jpg C:\Windows\Web\Screen\img100.old /Y
copy "%~dp0OSD_Failed.jpg" C:\Windows\Web\Screen\img100.jpg /Y

My script is derived from (https://yorkitacademy.wordpress.com/2012/11/20/customising-the-default-lock-screen-image-in-windows-8/). I just added the “%~dp0” variable to work in every Situation in SCCM, and also Changed the ACE to a SID, because on other languages, you can’t use “Administrator”.

And here is the second file, to set back the Standard LockScreen, Name the file SetStandard_Background.bat:
takeown /f C:\Windows\Web\Screen
takeown /f C:\Windows\Web\Screen\img100.jpg
icacls C:\Windows\Web\Screen /grant:r *S-1-5-32-544:F
icacls C:\Windows\Web\Screen\img100.jpg /grant:r *S-1-5-32-544:F
copy C:\Windows\Web\Screen\img100.old C:\Windows\Web\Screen\img100.jpg /Y

Your Package Directory should now Looks like this:
Package Directory

3. Create the Package
Now just create a Package with source Content of the Folder you created. Then add two programs to the packages, one for each Batch file. Your Package should then Looks like this:
SCCM Package

4. Add the Steps to the Task Sequence
Now add the steps to the Task sequence, and in the correct order. This means, we will set after the Windows Installation the failure Background as Standard LockScreen. And only if the Task Sequence reaches the end of the TS, the original LockScreen will be restored.
Add the Steps as marked out in this example TS:
TS Step1 TS Step 2

If now the Client has a error with installing an application or something else, when the OS was installed, your Windows 8.1 Machine will present you your LockScreen Picture:
OSD Failed

Hope this helps.


SCCM 2012 – Install .Net 4.5.2 on Windows 7 while on OSD

$
0
0

Hi,

I recently faced the issue, that the .Net 4.5.2 Application, which is working very well if deployed to a installed Windows 7 Client, but when I tried to use the same application within the OSD Task Sequence with System Center 2012 Configuration Manager, the Installation constantly fails with the Error:
Process 4000 terminated with exitcode: 16389

You will find some explanations to create a own archive, which will be extracted to allow the installation. Because the main problem is the extraction process while on Operating system deployment, what I could read about.
In anther Blog post (which I can’t find anymore) was mentioned to set the option “Run installation and uninstall program as 32-bit process on 64-bit clients.”. And that’s it!

Here you will find my working .Net 4.5.2 SCCM 2012 R2 SP1 Application usable for 32 and 64 bit client installations (also OSD).
First, copy the original Source to your SCCM package source directory and add it as Deployment Type source:
.Net 4.5.2 Source directory
You can find the source file here (Offline Installer): http://www.microsoft.com/en-us/download/details.aspx?id=42642

Configure the programs section for the Deployment Type as follows:
Net 4.5.2 program settings

My Installation command:
"NDP452-KB2901907-x86-x64-AllOS-ENU.exe" /norestart /q
The uninstall command:
"NDP452-KB2901907-x86-x64-AllOS-ENU.exe" /norestart /uninstall /q
And very important, activate “Run installation and uninstall program as 32-bit process on 64-bit clients.”

That last part is to define the Detection Method:
.Net 4.5.2 Detection method
I check the Registry Key HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client\Release for the value 379893.

Hope this helps.


SCCM 2012 – OSD PXE not working

$
0
0

Hi reader,

A few weeks ago I changed a lot within my LAB: I divided the Clients from the Servers into separate VLANs to have a more accurate Lab.
Now I wanted to install a VM on my Windows 10 Hyper-V environment, but when I tried to boot PXE, the machine stays for a while on this status:
Performing DHCP Negotiation
DHCP Negotiation

Afterwards the System told me, that there was DHCP failed:
DHCP failed

I thought, that this would be Firewall/DHCP/DHCP-Relay related issue, thus the clients did also not get a Lease on the DHCP Server, I only saw some Discovers and Offers, but not more. The firewall did not show any packets that would be dropped because of missing rules (but while searching the net I found this interesting Site about the Broadcast of DHCP Relays: https://supportforums.cisco.com/discussion/11853326/dhcp-relay-pxe-nexus-5500).

It took a while until I realized what I’m missing:
DHCP Boot Option 66 and 67!
*facepalm*

After configuring Boot Option 66 to my SCCM/WDS Server, and added \smsboot\x86\wdsnbp.com to Option 67 from my Client Scope, it worked like a charm.

Option 66: FQDN-Of-Server (IP is also usable)
Option 67: \smsboot\x86\wdsnbp.com
But wait!
With Option 67 set like above, UEFI Clients will not be able to boot the PXE Image, a Generation 2 Hyper-V VM will show you:
PE/COFF image invalid
“The PE/COFF image is invalid”

This means, that you should use the UEFI PXE image within boot Option 67
Option 67: SMSBoot\x64\wdsmgfw.efi
Afterwards Hyper-V Gen2 VMs and UEFI Clients will be able to boot from PXE, but BIOS based clients no longer. Here is the PXE Error PXE-E79 shown, when a Generation 1 Hyper-V machine tries to boot a UEFI image:
PXE-E79

So how can you get both?
Do not use DHCP options, use ip helpers to configure the PXE Server. The client will then automatically ask for the correct PXE boot image.

Hope this helps



ConfigMgr 2012 R2 SP1 – Windows 10 installed on X:

$
0
0

You are looking for a easy solution, to get a wim-File, copied directly from the Microsoft source, installed to the Computers drive C:? Here you get it!

I just recycle my BlogPost for the Windows 10 Release, because I did encounter quite the same Problem, but I’m ending up with the installed Windows on the Drive Letter x:.

Only a simple Change to your Task Sequence is needed, that those Image Installations will successfully be applied to the System drive C:.
Just add a “Set Task Sequence Variable” Action to your Task Sequence with Name OSDPreserveDriveLetter and value False. You can select this variable from the existing variable list:
Preserve Drive Letter

And with this, you can use your configuration as before. I normally use a variable, which is set, when the harddisc is formatted. Edit the Partition you want to assign the variable:

partition

PartitionPorperties

And in the “Apply Operating System” Action, the variable is then used:

ApplyOS

Hope this helps :)


Windows 10 – Language Packs localization for Built-In Groups

$
0
0

Since the deployments of Windows 10 take more and more steam on, new adventures are rising up. The last one I’ve seen, was the fact, that a deployed Windows 10 Enterprise 1511 en-US with included language packs is ending up with localized named Built-In Groups, when selected another User Interface, than en-US.

You might say, no problem with that, but in my opinion in some circumstances it is quite more easy, to be able to use the same group named “Administrators” on all Machines, instead of using an SID. Anyway, I could not find any explanation about this topic, and may someone comment what I’m doing wrong, or respond me on twitter (Tweet).
I’m using a very simple unattended file:
UnattendFile windows 10
I used the same structure within System Center Configuration Manager and variables for years now, and never faced this issue on a Windows 7 or 8 deployment.
I also checked the setupact.log and can determine, that the values from the unattend.xml gets applied:
unattendgc.log

But all the Built-In Groups are localized in German, so I’m ending up with a group named “Administratoren” instead of “Administrators”.
Is something wrong with my configuration, or is this a new behavior with Windows 10? Might someone can help me out on this, or can clarify that it happens to them aswell.


ConfigMgr 1602 – Windows 10 Servicing “Error 3”

$
0
0

Today I solved my Problem with the Service Plan of my Environment, it always ended up with the following Error in the Patchdownloader.log, this Log usually reside in “C:\Program Files\SMS_CCM\Logs”:
windows 10 servicing error 3

Failed to move C:\Windows\TEMP\CABD212.tmp to \\deheim.hosebei.ch\hosebeiDFSroot\Deployment\Packages\_UpdatePackages\20160116 - Win10x64\9a30f732-4d40-4b56-b86b-8253f80868a1.1\10586.0.160212-2000.th2_refresh_CLIENTENTERPRISE_VOL_x64fre_en-us.esd, error 3 Software Updates Patch Downloader 26.03.2016 19:16:01 7780 (0x1E64)
Will retry in 5000ms Software Updates Patch Downloader 26.03.2016 19:16:01 7780 (0x1E64)
Failed to move C:\Windows\TEMP\CABD212.tmp to \\deheim.hosebei.ch\hosebeiDFSroot\Deployment\Packages\_UpdatePackages\20160116 - Win10x64\9a30f732-4d40-4b56-b86b-8253f80868a1.1\10586.0.160212-2000.th2_refresh_CLIENTENTERPRISE_VOL_x64fre_en-us.esd, error 3 Software Updates Patch Downloader 26.03.2016 19:16:06 7780 (0x1E64)
Will retry in 5000ms Software Updates Patch Downloader 26.03.2016 19:16:06 7780 (0x1E64)
Failed to move C:\Windows\TEMP\CABD212.tmp to \\deheim.hosebei.ch\hosebeiDFSroot\Deployment\Packages\_UpdatePackages\20160116 - Win10x64\9a30f732-4d40-4b56-b86b-8253f80868a1.1\10586.0.160212-2000.th2_refresh_CLIENTENTERPRISE_VOL_x64fre_en-us.esd, error 3 Software Updates Patch Downloader 26.03.2016 19:16:11 7780 (0x1E64)
ERROR: DownloadContentFiles() failed with hr=0x80070003 Software Updates Patch Downloader 26.03.2016 19:16:11 2800 (0x0AF0)

I have configured a Windows 10 Servicing Plan within System Center Configuration Manager 1602 (Current Branch), and everytime I ran the Plan, or the plan was executed based on the schedule, it ended up with the Error:
Failed to move C:\Windows\TEMP\CABD212.tmp to \\deheim.hosebei.ch\hosebeiDFSroot\Deployment\Packages\_UpdatePackages\20160116 – Win10x64\9a30f732-4d40-4b56-b86b-8253f80868a1.1\10586.0.160212-2000.th2_refresh_CLIENTENTERPRISE_VOL_x64fre_en-us.esd, error 3
and
ERROR: DownloadContentFiles() failed with hr=0x80070003

In my case, the error appeared, because my Deployment Package contained the space character twice (once might give the same error): “20160116 – Win10x64”
All other Deployment Packages does have a space character within the Package Source Path, and they are working as expected, but the servicing plan does not work with a deployment Package with a space character in the Package Source path.

Hope this helps


ConfigMgr 1602 – Windows 10 Servicing Plans create continuous Software Update Groups

$
0
0

I was running the Service Plan for the Windows 10 enrollment within System Center Configuration Manager 1602 (Current Branch).
Unfortunately the option the use the same Software Update Group over and over again is missing:
Missing Option

The missing option is often used with the Automatic Deployment Rules (ADR), where you can configure to add the found updates to an existing Update Group:
windows10servicingPlan02

But without the opportunity to “Add to an existing Software Update Group” you will end up with an update group and a deployment pointing to the collection every time the service plan was running. Please vote on uservoice to tell Microsoft they should add this option to the service plans aswell:

How can we improve Configuration Manager?
  • 2 votes
  • 0 comments

Windows 10 Servicing Mode and ADR settings

Since updating to SCM 1511 the new Windows 10 Servicing mode has no option to 'add to an existing Software Update Group'.
Also the Automatic Deployment Rule properties tabs do not exist altogether as they did pre SCCM 1511. Yet they all exist for the Windows 10 Servicing Mode.

Always keep in mind to check uservoice if you see an improvement to ConfigMgr, maybe someone had already posted it, then you can only vote for it, have a look:
https://configurationmanager.uservoice.com/forums/300492-ideas


Windows and Local Administrator permission delegation

$
0
0

In this post, I would like to explain, what my experiences and solutions for the delegation of local Administrator permissions are. In a Client deployment Scenario, you will often be asked for a solution to provide IT Professionals and maybe also end users with local Administrator permissions. I will point out the most useful solutions which I do prefer.

  1. Local Administrator Account
  2. Permanent Local Administrator permissions for IT Professional
  3. Microsoft Local Administrator Password Solution for spontaneous permission
  4. Local Administrator delegation based on group per client

1. Local Administrator Account
Let me point this one out very clear: DO NOT USE THE SAME PASSWORD ON ALL YOUR CLIENTS FOR THE BUILT IN ADMINISTRATOR ACCOUNT!
Phew, sorry for that, but even if you rename the account, never use the same Password on all your clients. I would suggest to set an unknown password, or manage the password with the local administrator password solution from Microsoft (see Chapter 3).
If you’re setting a password known to the IT Department (or someone else), make sure you have implemented a solution to change the password on a regular base, and again set different passwords each client!

2. Permanent Local Administrator permissions for IT Professional
This is nothing special, based on Active Directory, you can create groups, where the Administration Accounts of the IT Department can be added. You can then use Restricted Groups from the Group Policy to add the required groups to the Built-In Administrators group of the client. I would not use the Group Policy Preference for this setting, in some circumstances (like a “gpupdate /force”), the Group Policy preferences might not be executed.

3. Microsoft Local Administrator Password Solution for spontaneous permission
Microsoft has released a handy tool to manage the password of a user Account on the Client, this is very useful in the event of a user without a network connection required to get local Administrator permission. You can manage the Built-In Administrator Account or another Account that you have previously created, the corresponding password will be saved to Active Directory, a Schema Update is mandatory to get the required Attributes. One small hint: If you reinstall a client, make sure to clear the expiration date of the password within the AD, or the client will not create a password on the Account. See this blog for further information about LAPS: LAPS (on dirteam.com).

4. Local Administrator delegation based on group per client
But what if you need to grant local Admin permission only to one computer for one user? And you might also want to get easily reported, which client do have Endusers with local Admin rights. This requirement can be achieved with the following solution, and starting with creating a group per client, where a single, or multiple End-users should have admin permission. Make sure that you will name all groups with the same name, except the computer name of course. In this example, my group convention leads me to the following group name:
G-LocalAdmin-%computername%
So in fact, for my computer Rudolph, a group named “G-LocalAdmin-Rudolph” is created:
create group
Create a group for every client which is required to permit local Admin to a user, and you can also use local Groups to nest the global group if you like to.
Now go ahead and open or create a GPO which does apply on the designated clients, navigate to the “Local User and Groups” section, and add a setting for the “Administrators (built-in)”:
Group Policy add admin
Make sure that you select “Update” as Action, as Group Name select “Administrators (built-in)” from the drop down and add the Description, otherwise the Description will be cleared on the clients:
Group Policy Preference
Now it is time to fill the members of the group, click on “Add..” in the lower section of the wizard, and paste your corresponding value into the box. In my case the string is “deheim\G-LocalAdmin-%computername%”, make sure to change this value to your requirements:
Add group to admin gpo gpp
When you have added the group, you will have to change the to common and activate the check box at “Remove this item when it is no longer applied”, this ensures together with the Update Action of the GPP that the group will be removed, as soon as the Item-Level targeting is no longer true. Also activate the check box on item-level targeting and click on “Targeting…” afterwards:
GPP common settings
In the opened window called Targeting Editor click on “New Item” and select “LDAP Query”, configure the added item by just copy the following query to the filter (&(&(sAMAccountType=805306369)(objectCategory=computer)(objectClass=computer)(|(samAccountName=%computername%$))(managedBy=*)))”. Your targeting editor should then looks like the following picture:
gpo gpp ldap query
Finish the wizard by click on “OK” twice.
The last step would be to add the created group to the ManagedBy attribute of the client. You can do this through the Active Directory Users and Computers mmc:
Computer Account ManagedBy
Without adding the ManagedBy attribute, the LDAP Query would not be true, and the group will be removed from the local Built-In Administrators group. Please mind, that this not magically will add the group or user from the managedBy attribute, you can add whatever you want to this attribute and the GPP will be triggered.
But you can also easily report all the clients which have given admin permissions to only some of your users.


ConfigMgr – Windows 10 Feature Update without a Task Sequence

$
0
0

Today I would like to talk about the upcoming update cycles you have to do, when you are using Windows 10 Current Branch or Current Branch for Business. This means, if you have started to install Windows 10 1507 (which represents the first Windows 10 Release, some may call it also RTM) in spring of last year, you will be soon required to upgrade to a newer version of Windows 10. Also if you are using Windows 10 1511, with the upcoming creators update, the 1511 version of Windows 10 will be soon unsupported, following the official guidelines.
winver.exe 1607

This means you are required to plan a rock solid update mechanism, that respects your needs in order to satisfy the business in a client perspective. One of the most important advises for planning your update infrastructure: Create steps that you can reuse whenever a new image or version of Windows 10 is released, where it is possible.
For the past it have might been the best option, to use a System Center Configuration Manager (ConfigMgr) Current Branch update Task Sequence, if you wanted to fully control all aspects of an update installation. The options within this Task Sequence are quite similar to the existent operating system deployment Task Sequences. But in larger environments or with locations that are not well-connected to a distribution point, this can be very hard to run successfully, so the Servicing model might be an option. And if you think about the regular consumers, they always update Windows 10 with the servicing model, which means that the new version gets installed like a regular Windows Update. With this information you can come to the conclusion, that Microsoft prefers the option of the servicing model. Even with a ConfigMgr Infrastructure the servicing model can be helpful, if a client can download the new Windows Version from the Windows Update source, rather than download it from a DP (ConfigMgr Distribution Point) through a company VPN.

Now you might want to ask me: But I have multiple languages to support and servicing model only updates the base language. HOW U HANDLE THAT?
Well, there is a kind of messy part, and an easy part to handle that. Let me first talk about the easy part: The easy part is as follows, you can simply use a SetupConfig.ini file which points on a folder, where the Language Packs are available, and the Windows setup will install those Language Packs automatically. The usage of a SetupConfig.ini file is well explained on this blog on windows-noob.com.
And now here comes the messy part: What if you have to support more than 20 languages? And more on: All clients have as base language en-US (English United States), and they may have one or more languages installed?
Unfortunately there does not exist an option, or I did not find it like many others, to report the installed language packs within ConfigMgr, for using it within a query based collection. But you can add a WMI class to your clients and collect this class through the hardware inventory. This process has already been documented on the systemcenterdudes.com blog.
Now you can create collections or use this information in other ways to deploy the language packs to the correct clients.

The next big Question will be: But with the new Version, I will get the Windows Store-App Candy Crush again, which I have removed from the image. With the servicing model I can’t modify the image. HOW U HANDLE THAT?
There are different options to modify the freshly installed Windows 10, and one of them you can use within a regular OSD Task sequence as well, you may just change the way it gets executed. So if you need to modify System settings like which language will be used for a default user, or how the default start menu should look like, you can use a script, which will be executed at the end of the Windows 10 upgrade. To use this option, you simply have to add the following line to your SetupConfig.ini:
PostOOBE=C:\LP\Scripts\CommandAfterInstall.bat
Obviously the script has to exist at the location, I will point out how I achieved this later in this blog.
The second option which you can use to modify the System is when the user has logged on, this method uses the SetupCompletes.cmd option and is explained on this MSDN Site.
But as stated on the MSDN site: “This script runs immediately after the user sees the desktop”
So it might not be the best option.

So let’s go on and see, how I did the Script stuff for the upgrade.
First I created a Folder where my German language pack resides and I copied the language pack inside it and my 3 other required Files as well, which I will explain immediately:
Package Folder
Now I will show you the content of “Copy_LP_de.bat”:
mkdir c:\LP
mkdir c:\LP\Scripts
mkdir c:\LP\LP
copy "%~dp0*.cab" c:\LP\LP /Y
copy "%~dp0CommandAfterInstall.bat" c:\LP\Scripts /Y
mkdir "%systemdrive%\Users\Default\AppData\Local\Microsoft\Windows\WSUS\"
copy "%~dp0SetupConfig.ini" "%systemdrive%\Users\Default\AppData\Local\Microsoft\Windows\WSUS\" /Y

This batch file can be used for every language and also if you are using feature packs or even Language Interface Packs.
Now lets talk about the “CommandAfterInstall.bat”, which is quite a short speech: You can start whatever you like (afaik). In my case, I just created a folder to be sure that the batch gets executed.
And beside the language pack, the last two lines are the most important. Those create the required WSUS folder within the Default User profile, and copies our “SetupConfig.ini” file to this location. My example of the SetupConfig.ini is quite simple:
[SetupConfig]
InstallLangPacks = C:\LP\LP
PostOOBE=C:\LP\Scripts\CommandAfterInstall.bat

SetupConfig.ini
So my example does instruct the Windows Installation to watch out in “C:\LP\LP” for language packs and will start “C:\LP\Scripts\CommandAfterInstall.bat” after the installation succeeds.
For a full list of the available parameters that you can use within the SetupConfig.ini refer to this MSDN site.

Happy updating!


ConfigMgr – Windows 10 Servicing – Step by Step

$
0
0

Today I would like to show you, how you can implement an Upgrade of a Windows 10 Installation through the Servicing Option.
I always think of two things, when I have to decide to use an Upgrade Task Sequence or the Servicing Model, and those are:

  • Do I want to use the Option that the clients will download the Windows 10 Sources from the Microsoft Update Servers?
  • When I use an Upgrade Task Sequence, I can copy most of the steps from the regular OSD Task Sequence
  • But for this blog post, I would like to show my setup for the servicing model.

    First of all, I have already written a post about the Update process in a slightly overview manner, you will find this post here: My old post

    The first step would be to determine which packages you would like to implement for the upgrade. Based on the fact, that I use English as base language, I will add the Feature on Demand (FoD) packages, and I will also add the feature package NetFx3. My Setup does also contain the German Langauge, which requires me to add the corresponding Language Pack and FoD Packages. The following picture shows the folder of my Packages which I want to include within the Windows 10 Installation:

    When this is done, you will have to decide, where you would like to store the packages and also some script files on the System Disk of the current Client. I have decided to create a folder named C:\LP, which is hidden, and two subfolders called LP and Scripts, I would also recommend to modify the default User Permissions, if you don’t want that standard users can change the scripts.

    To achieve the copy jobs which are required, I will come back to those scripts later, I have decided to use Configuration Items, rather than an Application or an Old-School Package within the Software Library. But this will require that my clients are able to access those files, because they will not download it from a Distribution Point. I am using Distributed File Services (DFS) to have a single UNC Path, where the clients can download the packages (with BITS of course).
    I have decided where my package location resides and have copied all the required packages and scripts to this location:

    Then I went on and created a Configuration item named “Windows 10 Servicing CI”:

    I only selected Windows 10 (x64):

    Within the next step of the Wizard, click on “New…” to add a setting, and the following Windows appears:

    Make sure to have selected the “Setting Type” Script, and as “Data Type” “String”, as shown in the picture above. Afterwards click on “Add Script…” within the Discovery Script Section, and the following script block windows will appear:

    Make sure that “Windows Powershell” is selected as script language. The script will simply check both file locations, and if the size is not the same, the CI will be reported as non-compliant. You may want to extend the detection script to your needs, as example if you have multiple languages and want to copy only some languages to the client. I have used the following script for this purpose (you will find a zip Download at the end of the blog as well):
    #Variables
    $LocalFolderLP = "C:\LP\LP"
    $PathToLanguagePacks = "\\deheim.hosebei.ch\hosebeiDFSroot\Deployment\OS\Windows 10\LanguagePacks\1703"

    $Compliance = "Non-Compliant"

    #Receive transferred jobs, but not yet finished
    $bitstransfers = Get-BitsTransfer -AllUsers
    foreach($bitsjob in $bitstransfers) {
    if($bitsjob.Jobstate -eq "Transferred") {
    #End old Transfers due script execution errors
    Complete-BitsTransfer -BitsJob $bitsjob
    }
    }

    #Start Main Script
    If((Test-Path $LocalFolderLP) -eq $false) {
    $Compliance = "Non-Compliant"
    }
    else {
    #Measure both Locations
    $SizeOfLPsSource = Get-ChildItem -Path $PathToLanguagePacks -Filter *.cab | Measure-Object -property length -sum
    $SizeOfLPsDestination = Get-ChildItem -Path $LocalFolderLP -Filter *.cab | Measure-Object -property length -sum
    If($SizeOfLPsSource.sum -ne $SizeOfLPsDestination.Sum) {
    $Compliance = "Non-Compliant"
    }
    else {
    $Compliance = "Compliant"
    }
    }
    #Return the result
    $Compliance

    Close this Windows by a click on “OK”. Then go ahead and click on “Add Script…” witin he Remedation Script section, and add the following script to the script block:

    #Copy the Language Pack Files
    Function Start-LPBitsJob([System.IO.FileInfo]$CABFileToCopy, [string]$LocalLPFolder) {
    $BitsJob = $null
    $BitsJob = Start-BitsTransfer -Source $CABFileToCopy.FullName -Destination $LocalLPFolder -TransferType Download -Asynchronous -DisplayName "CAB Downloads"
    }

    #Variables
    $LocalFolderLP = "C:\LP\LP"
    $PathToLanguagePacks = "\\deheim.hosebei.ch\hosebeiDFSroot\Deployment\OS\Windows 10\LanguagePacks\1703"

    #Start Main Script
    if((Test-Path $LocalFolderLP) -eq $false) {
    New-Item $LocalFolderLP -ItemType Directory
    }
    $MakeHidden = Get-Item "C:\LP" -Force
    $MakeHidden.Attributes="Hidden"
    if((Test-Path $LocalFolderScripts) -eq $false) {
    New-Item $LocalFolderScripts -ItemType Directory
    }

    $CABFilesToCopy = Get-ChildItem -Path $PathToLanguagePacks\* -Include *.cab
    foreach($cabFile in $CABFilesToCopy) {

    if($cabFile.length -ne (Get-Item ($LocalFolderLP + "\" + $cabFile.Name)).Length) {
    #Write-Host "not same"
    Start-LPBitsJob $cabFile $LocalFolderLP
    }
    else {#Write-Host "same"
    }
    }

    $AllBitsDownloads = Get-BitsTransfer -Name "CAB Downloads"
    $DLFinishedLoop = $false
    while ($DLFinishedLoop -eq $false) {
    $DLFinished =$true
    foreach($BITSDownload in $AllBitsDownloads) {
    if($BITSDownload.JobState -ne "Transferred") {
    $DLFinished = $false
    }
    }
    if($DLFinished -ne $false) {
    $DLFinishedLoop = $true
    }

    sleep 1
    #write-host "loop"
    }

    #Now finish all Transfers
    $AllBitsDownloads | Complete-BitsTransfer

    As you can see, I’m using a BITS Transfer to download the packages and all packages are checked (based on the size), and a specific package is only downloaded if required. For more information about starting a BITS download through Powershell consult this Microsoft document: Using Windows PowerShell to Create BITS Transfer Jobs
    Your remediation script block should look like this:

    When this is done, we can switch to the “Compliance Rule” Tab and click on “New…”:

    Fill the opened window with the required information, make sure to check the Box at “Run the specified remediation script when the setting is noncompliant”:

    By clicking on OK twice, the first setting within the configuration item is finished. Now it is time to add the setting to copy the setupconfig.ini file, which is required to instruct the Windows Upgrade to use the downloaded packages and to execute a script after the installation. For more information about the setupconfig.ini refer to this Microsoft Document: Use Setupconfig.ini to install Windows
    My SetupConfig.ini is quite simple, I’m still using the same as outlined in the old post.
    Now a click on “New…” will open again a new setting:

    In the opened window, fill out the settings as shown below:

    Add the following script to the Discovery section:

    #Path to setupconfig File
    $SourceFileLocation = "\\deheim.hosebei.ch\hosebeiDFSroot\Deployment\OS\Windows 10\LanguagePacks\1703\SetupConfig.ini"

    $Compliance = "Not-Compliant"
    if((Test-Path -Path "$env:SystemDrive\Users\Default\AppData\Local\Microsoft\Windows\WSUS\setupconfig.ini") -eq $false) {
    $Compliance = "Not-Compliant"
    }
    elseif((Get-Item "\\deheim.hosebei.ch\hosebeiDFSroot\Deployment\OS\Windows 10\LanguagePacks\1703\SetupConfig.ini").Length -ne (Get-Item "$env:SystemDrive\Users\Default\AppData\Local\Microsoft\Windows\WSUS\setupconfig.ini").Length) {
    $Compliance = "Not-Compliant"
    }
    else {
    $Compliance = "Compliant"
    }
    $Compliance

    My remediation script, which will copy the setupconfig.ini to the correct place does not change the folder permissions of the WSUS folder. I would recommend for your environment to change the folder, or at least the file permission, that a regular user can’t modify the setupconfig.ini File. This is my remediation script for the ini file:

    if((Test-Path "C:\Users\Default\AppData\Local\Microsoft\Windows\WSUS") -eq $false) {
    New-Item -Path "C:\Users\Default\AppData\Local\Microsoft\Windows\WSUS" -ItemType Directory
    }
    Copy-Item -Path "\\deheim.hosebei.ch\hosebeiDFSroot\Deployment\OS\Windows 10\LanguagePacks\1703\SetupConfig.ini" -Destination "$env:SystemDrive\Users\Default\AppData\Local\Microsoft\Windows\WSUS\SetupConfig.ini" -Force

    When you have added both scripts, switch to the Compliance Rules Tab, and add a new rule by a click on “New…”, fill out the opened rule window as in the following picture:

    Make sure again to have ticked the box to run the remediation script.
    And the last CI setting will copy the scripts that are required to be executed after the Windows Upgrade is done, but before a user can logon. The process is the same like for the two settings we already have created. Here is the Discovery Script which I’m using:

    $LocalFolderScripts = "C:\LP\Scripts"
    $SourceFileLocation = "\\deheim.hosebei.ch\hosebeiDFSroot\Deployment\OS\Windows 10\LanguagePacks\1703"

    $Compliance = "Not-Compliant"

    $AllLocalScripts = Get-ChildItem -Path $LocalFolderScripts\* -Include *.bat,*.vbs,*.ps1
    $AllSourceScript = Get-ChildItem -Path $SourceFileLocation\* -Include *.bat,*.vbs,*.ps1
    if($AllLocalScripts.Count -ne $AllSourceScript.Count) {
    $Compliance = "Not-Compliant"
    }
    $SizeOfScriptsSource = Get-ChildItem -Path $SourceFileLocation\* -Include *.bat,*.vbs,*.ps1 | Measure-Object -property length -sum
    $SizeOfScriptsDestination = Get-ChildItem -Path $LocalFolderScripts\* -Include *.bat,*.vbs,*.ps1 | Measure-Object -property length -sum
    if($SizeOfScriptsSource.sum -ne $SizeOfScriptsDestination.sum) {
    $Compliance = "Not-Compliant"

    }
    else {
    $Compliance = "Compliant"
    }
    $Compliance

    And this is the remediation script:

    Function Start-BitsJob([System.IO.FileInfo]$FileToCopy, [string]$LocalFolder) {
    $BitsJob = $null
    $BitsJob = Start-BitsTransfer -Source $FileToCopy.FullName -Destination $LocalFolder -TransferType Download -Asynchronous

    while (($BitsJob.JobState -eq "Transferring") -or ($BitsJob.JobState -eq "Connecting")) { sleep 5;} # Poll for status, sleep for 5 seconds, or perform an action.

    Switch($BitsJob.JobState)
    {
    "Transferred" {Complete-BitsTransfer -BitsJob $BitsJob}
    "Error" {$BitsJob | Format-List } # List the errors.
    default {"Other action"} # Perform corrective action.
    }
    }

    $LocalFolderScripts = "C:\LP\Scripts"
    $PathToLanguagePacks = "\\deheim.hosebei.ch\hosebeiDFSroot\Deployment\OS\Windows 10\LanguagePacks\1703"

    if((Test-Path "C:\LP\Scripts") -eq $false) {
    New-Item -Path "C:\LP\Scripts" -ItemType Directory
    }

    $ScriptFilesToCopy = Get-ChildItem -Path $PathToLanguagePacks\* -Include *.ps1,*.vbs,*.bat
    foreach($ScriptFile in $ScriptFilesToCopy) {
    if($ScriptFile.length -ne (Get-Item ($LocalFolderScripts + "\" + $ScriptFile.Name)).Length) {
    #Write-Host "not same"
    Start-BitsJob $ScriptFile $LocalFolderScripts
    }
    else {#Write-Host "same"}
    }

    When you have finished adding the third setting, your Configuration Item should look like this:

    If you click on Next, the wizard will show you the created Compliances Rules according to the settings, make sure that “Remediate” is on Yes:

    Finish the wizard by clicking on Next twice and close it afterwards. Now we need to create a Baseline and just add our Compliance Item to it:

    After a click on OK, the baseline is created and ready to be deployed on a collection. Within the deployment wizard of the baseline, make sure to tick the check box at “Remediate noncompliant rules when supported”:

    Now everything is quite good and you can create a collection based on the baseline:

    And here is my batch file which I run after the Windows 10 Upgrade:
    mkdir C:\LP\1703_OK
    powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\LP\Scripts\Remove-Apps.ps1"

    The PowerShell Script “Remove-Apps.ps1” removes Universal apps which I don’t want on the clients. This is the content of Remove-Apps.ps1:

    #Initalize Array
    $AppstoRemove = New-Object System.Collections.ArrayList

    #Add Apps to Array
    $AppstoRemove.Add("Microsoft.NetworkSpeedTest_1.0.0.23_x64__8wekyb3d8bbwe") #NetworkSpeedTest
    $AppstoRemove.Add("46928bounde.EclipseManager_2.2.1.31_neutral__a5h4egax66k6y") #Eclipse Manager
    $AppstoRemove.Add("6Wunderkinder.Wunderlist_3.6.25.0_x64__b4cwydgxqx59r") #Wunderlist
    $AppstoRemove.Add("Microsoft.MicrosoftOfficeHub_17.8017.5925.0_x64__8wekyb3d8bbwe") #Get Office Sneak App
    $AppstoRemove.Add("Microsoft.BingTranslator_4.7.0.0_x64__8wekyb3d8bbwe") #Bing Translator
    $AppstoRemove.Add("D5EA27B7.Duolingo-LearnLanguagesforFree_2017.112.1.0_x64__yx6k7tf7xvsea") #Language Learning App
    #$AppstoRemove.Add("Microsoft.SkypeApp_11.12.112.0_x64__kzf8qxf38zg5c") #Skype for Business App
    #$AppstoRemove.Add("Microsoft.Office.OneNote_17.7967.57741.0_x64__8wekyb3d8bbwe") #OneNote App

    $AppstoRemove | Remove-AppxPackage

    You might want also to configure the Language settings as they were before. Then you can use the solution from Roger Zander, to apply Language Settings with an XML: Windows 10 MUI challenge
    Here you will find a Zip-File with all my scripts used within this blog: Windows 10 Upgrade Scripts

    Now you can deploy the upcoming release to your clients, just like a regular update.

    If you think this post was useful, please leave a comment, and if you see issues or you can recommend better techniques, leave a comment as well, or get in touch with me on twitter.



    ConfigMgr – My Guide for a SCCM driven Windows 10 Installation

    $
    0
    0

    In this blog I would like to give an overview of my Windows 10 Installation, since this has changed a lot to previous versions of Windows.
    This blog will cover the following topics:

    • Windows 10 Image Customization
    • Windows 10 Unattended File
    • Windows 10 Language Pack (MUI) Integration
    • Optional: Windows 10 with .Net feature

    The blog is based on Windows 10 1703:

    Windows 10 Image Customization
    Here is nothing to do. In most of the deployments I’ve seen, we did not make changes to the image or wim-file itself. I always did this in previous versions of Windows for have languages added and Windows features as well. But starting with Windows 10, I stopped those task, and moved to the “Do everything possible within the Task Sequence”. The main reason for this is to have those steps available for OSD and a Feature Upgrade as well.
    A good reason to modify the image is, if your installation process should consume less time. Because installing language packs or other Software can stretch the installation time.

    Windows 10 Unattended File
    In earlier Versions of Windows I often used a unattended file only to set the variables for the languages, I do now the opposite, and I also use more settings within the unattend file. Due to the fact, that I always use the en-US base image, my language settings looks like the following picture:

    The language settings within the OOBE section are the same. But I do have an additions to suppress the Wireless Setup (HideWirelessSetupInOOBE), which can interrupt the task sequence progress, or at least the progress is not visible. And also the MachineOOBE will be skipped:

    With those settings I can start building the Task Sequence within System Center Configuration Manager.

    Windows 10 Language Pack (MUI) Integration
    I install the language packs within the Windows PE phase. For this, I need to create a package, containing all the .cab files that I wanted to install through the Task Sequence. This includes the language pack for Swiss-German and the Feature on Demand (FoD) packs for the same language as well. In my case, the package source content folder looks like the following picture:

    As you can see in the screenshot, I also added a batchfile to install the language packs with dism, and a XML which is later described. Here is the dism command within the batch:
    dism.exe /image:%OSD_System%\ /add-package /packagepath:%~dp0
    The variable “%OSD_System%” which is used in the command above is set through the partitioning step previous in the task sequence.
    So I can now add a command line step to my Task Sequence which I have simply created through the wizard. It is important to add the step after the windows image was applied:

    This will install all the Language Packs and other Feature on Demand Packs, which resides in the Package folder. This process is executed within the Windows PE phase of the Windows 10 Installation.
    Now, all the required Package are installed, and the system will be installed with a Base Language of US english, but with a Swiss-German Keyboard Layout (configured through the unattended.xml). The next step is to instruct Windows to use the German Language Pack as Default User Interface Language, and the regional settings should be changed to Switzerland as well. For this, I will implement the solution which Roger Zander (Twitter) is providing on his blog (see Source). I will outline the required steps below.
    The first step is to create the XML file which will be used in the next step. I just also add this XML file to my existent Language and FOD package (see Screenshot above). This is the content of the XML (copy from Rogers blog):


    <gs:GlobalizationServices xmlns:gs="urn:longhornGlobalizationUnattend">
    <!--User List-->
    <gs:UserList>
    <gs:User UserID="Current" CopySettingsToSystemAcct="true" CopySettingsToDefaultUserAcct="true" />
    </gs:UserList>

    <!--Display Language-->
    <gs:MUILanguagePreferences>
    <gs:MUILanguage Value="de-DE" />
    <gs:MUIFallback Value="en-US" />
    </gs:MUILanguagePreferences>

    <!--User Locale-->
    <gs:UserLocale>
    <gs:Locale Name="de-CH" SetAsCurrent="true" ResetAllSettings="false"/>
    </gs:UserLocale>

    <!--input preferences-->
    <gs:InputPreferences>

    <!--de-CH-->
    <gs:InputLanguageID Action="add" ID="0807:00000807" Default="true"/>

    <!--en-US-->
    <gs:InputLanguageID Action="remove" ID="0409:00000409"/>

    <!--de-DE-->
    <gs:InputLanguageID Action="remove" ID="0407:00000407"/>

    <!--fr-CH-->
    <gs:InputLanguageID Action="remove" ID="100c:0000100c"/>
    </gs:InputPreferences>

    <!--location-->
    <gs:LocationPreferences>
    <gs:GeoID Value="223"/>
    </gs:LocationPreferences>
    </gs:GlobalizationServices>

    Then add another step to your Task Sequence where you just start the following command:
    control intl.cpl,, /f:"lang_de-CH.xml"
    Make sure that you add this step after the Installation of Windows and Configuration Manager Client. This would look like the following picture:

    And then I’m mostly done with the Windows 10 Image itself. Removing Windows Store apps or other settings can be done afterwards, or within the Task Sequence too. But as written above I want to add the .Net 3.5 feature to the Task Sequence, so this leads to the last topic of this blog.

    Optional: Windows 10 with .Net feature
    I do also add the Windows 10 .Net feature within the Windows PE phase, and before the Language Packs get installed. First, you will need to create a package, that contains the payload of the .Net feature installation. Copy the SXS folder from a Windows 10 Installation Media to a Folder, from which you create a ConfigMgr package afterwards:

    Similar to the language pack package, I created a install.bat file, to start the installation with DISM, the command within the batch is outlined below:
    dism.exe /image:%OSD_System%\ /enable-feature /featurename:NetFx3 /source:%~dp0 /all
    Then create a package, and add a step to the task sequence after the Language Pack installation:

    As outlined in Rogers blog, the command will end with an exit code of 1, you should consider to add this exit code as a success-reboot required. You can add this exit code to the command line step:

    Results
    After the Task Sequence has finished, the system will welcome you with the correct language:


    The language settings are like configured within the xml:

    And also the .Net Feature is installed:

    Happy Windows 10 Deploying!


    Windows 10 1703 – Remove Universal Windows Platform (UWP) Apps

    $
    0
    0

    Hi reader,

    I would like to share my script to remove windows universal apps, which I have tried to make it simple as possible.
    First let me explain, that there seems to exist two different types of Apps which reside within the Windows 10 Image. You can list them with Get-AppxPackage and Get-AppxProvisionedPackage (you need Administrator permission to do so):

    And both of those Apps require a different Powershell command to remove the App. For the provisioned UWP Apps, you need to use Remove-AppxProvisionedPackage (Technet Source). The other UWP Apps can be removed with Remove-AppxPackage (TechNet Source).

    This was leading me to create a Powershell Script, where you can easily create Output Files of the Apps. Afterwards you can edit the output files, and use them as Input File to remove the apps from the system.
    The following command is required, to export the provisoned Apps:
    .\ManageUWPApps.ps1 -ScriptFunction Export
    The Script will generate a csv called ProvisionedApps.txt where the powershell Script resides, unless you had defined the parameter -Workfile (See Script Description for more Information).
    You can then delete all the Apps, which should reside on the system, and only include Apps, which should get removed. In the following example, only OneNote and the Wallet gets removed:

    To remove the provisioned Apps within the csv, you have to start the Script with different parameters:
    .\ManageUWPApps.ps1 -ScriptFunction RemoveApps -WorkFile 'C:\temp\ProvisionedApps.txt'

    For the other apps, to export you need to use ExportApps:
    .\ManageUWPApps.ps1 -ScriptFunction ExportApps
    This will create an output file named AllOtherApps.txt, unless specified with the Workfile parameter.

    To remove the Apps, edit the exported List as above, and use the File as import file within the following command:
    .\ManageUWPApps.ps1 -ScriptFunction RemoveOtherApps -WorkFile 'C:\temp\AllOtherApps.txt'

    You can download the Script from my OneDrive, or you can try copy/paste from blog (be aware of special Chars) at the end of this blog.
    Download Link txt: https://1drv.ms/t/s!Aq0GcVCqC0Rlor0FIqoDPUF2ghrbrA

    Hope this helps.

    The Script:
    # Description
    #-> For Exports: Existing Files with same Name will be overwritten!

    # Export Examples:
    # .\ManageUWPApps.ps1 -ScriptFunction Export
    # -> This will export the provisioned Apps to a CSV File located where the Powershell Script resides, at it will overwrite an existent File named ProvisionedApps.txt
    #
    # .\ManageUWPApps.ps1 -ScriptFunction Export -WorkFile c:\temp\11111.txt
    # -> This will export the provisioned Apps to a CSV File located at c:\temp\11111.txt, at it will overwrite an existent File
    #
    # The paramter switch "ExportApps" works as above
    # .\ManageUWPApps.ps1 -ScriptFunction ExportApps
    # -> This will export the other Apps to a CSV File located where the Powershell Script resides, at it will overwrite an existent File named AllOtherApps.txt

    # Remove Apps Examples
    # .\ManageUWPApps.ps1 -ScriptFunction RemoveApps -WorkFile 'C:\temp\ProvisionedAppx.txt'
    # -> This will remove all provisioned Apps which reside in the omitted text file (same layout as export required!)
    #
    # .\ManageUWPApps.ps1 -ScriptFunction RemoveOtherApps -WorkFile 'C:\temp\AllOtherApps.txt'
    # -> This will remove all other Apps which reside in the omitted text file (same layout as export required!)

    #See blog: https://blog.hosebei.ch to be created :)

    #### Require Parameters

    #Force to use Selection of Execution
    Param(
    [Parameter(mandatory=$true)][string]$ScriptFunction,
    [string]$WorkFile
    )

    #### Functions

    #Create OutPutFile Function
    Function Create-OutPutFile {
    Param(
    [string]$OutPutFile
    )

    if($OutPutFile -eq "") {
    Write-Error "No OutpuFile Name was ommited or generated. Script aborted"
    exit(1)
    }

    #Export Provisioned Apps
    $apps = Get-AppxProvisionedPackage -Online | select DisplayName,PackageName
    #Delete Export File if already existent
    if(Test-Path $OutPutFile) {
    Remove-Item $OutPutFile -Force
    }
    $apps | export-csv -Path $OutPutFile -Delimiter "," -NoTypeInformation

    }

    #Creat Export file for Apps
    Function Create-OutPutFileApps {
    Param(
    [string]$OutPutFile
    )

    if($OutPutFile -eq "") {
    Write-Error "No OutpuFile Name was ommited or generated. Script aborted"
    exit(4)
    }

    #Export Provisioned Apps
    $apps = Get-AppxPackage -AllUsers | select Name,PackageFullName
    #Delete Export File if already existent
    if(Test-Path $OutPutFile) {
    Remove-Item $OutPutFile -Force
    }
    $apps | export-csv -Path $OutPutFile -Delimiter "," -NoTypeInformation

    }

    #Remove Provisionied Apps Function
    Function Remove-ProvisionedApps {

    Param(
    [string]$InPutFile
    )

    if(Test-Path $InPutFile) {
    $workfile = $InPutFile
    }
    else {
    Write-Warning "Input File was not accessible! The following file name was tried:"
    Write-Warning $InPutFile
    exit(3)
    }

    #read input file
    $AppsToRemove = import-csv -Path $workfile -Delimiter ","

    #execute appx removal
    foreach($appToRemove in $AppsToRemove){

    Write-Host ("The following app will be removed: " + $appToRemove.DisplayName)
    Remove-AppxProvisionedPackage -Online -AllUsers -PackageName $appToRemove.PackageName

    }

    }

    Function Remove-AllOtherApps {
    Param(
    [string]$InPutFile
    )

    if(Test-Path $InPutFile) {
    $workfile = $InPutFile
    }
    else {
    Write-Warning "Input File was not accessible! The following file name was tried:"
    Write-Warning $InPutFile
    exit(7)
    }

    #read input file
    $AppsToRemove = import-csv -Path $workfile -Delimiter ","

    #execute appx removal
    foreach($appToRemove in $AppsToRemove){

    Write-Host ("The following app will be removed: " + $appToRemove.Name)
    Remove-AppxPackage -AllUsers -Package $appToRemove.PackageFullName

    }

    }

    #### Main Script

    #Main Script Switch Section
    switch ($ScriptFunction) {

    "Export" {
    #Check if WorkFile was defined
    if($WorkFile -eq "") {
    #Generate Workfile Path
    $WorkFile = $PSScriptRoot + "\ProvisionedApps.txt"

    }
    #Start Export
    Create-OutPutFile -OutPutFile $WorkFile
    }

    "ExportApps" {
    #Check if WorkFile was defined
    if($WorkFile -eq "") {
    #Generate Workfile Path
    $WorkFile = $PSScriptRoot + "\AllOtherApps.txt"

    }
    #Start Export
    Create-OutPutFileApps -OutPutFile $WorkFile
    }

    "RemoveApps" {
    #Check for Input File
    if($WorkFile -eq "") {
    #Generate Workfile Path
    Write-Warning "You must provide the InputFile Path when removing provosionied apps!"
    Write-Warning "Example: ManageUWPApps.ps1 -ScriptFunction RemoveApps -WorkFile 'C:\temp\ProvisionedAppx.txt'"
    exit(2)

    }
    else {
    Remove-ProvisionedApps -InPutFile $WorkFile
    }

    }

    "RemoveOtherApps" {
    #Check for Input File
    if($WorkFile -eq "") {
    #Generate Workfile Path
    Write-Warning "You must provide the InputFile Path when removing provosionied apps!"
    Write-Warning "Example: ManageUWPApps.ps1 -ScriptFunction RemoveOtherApps -WorkFile 'C:\temp\AllOtherAppx.txt'"
    exit(6)

    }
    else {
    Remove-AllOtherApps -InPutFile $WorkFile
    }

    }

    default {write-host "See description at top of the script, and/or visit my blog"}

    }


    Windows 10 – Remove Windows.old Folder

    $
    0
    0

    Long time no see, huh? Now I’m back with a new post about removing the Windows.old folder after a feature Upgrade.
    Recently I seen this on twitter, a commented it with: Why don’t you let the automation from Windows 10 let it do. But since then, I was in a project, where the removal of this folder was required, and within the Upgrade Task Sequence. I thought, this is easy, starting the Scheduled Task should do the job…

    You can easily start this task within a command line, but since this does not solve the “problem”, I don’t provide this command. But I will provide a more useful information. You can use cleanmgr.exe, yes, this is the “Disk Cleanup” which is included since some versions of Windows:

    But this is a GUI, how can we use this within in TS? I used my prefered search engine, and found a solution. You can create a Cleanup Profile, save this to registry, and then run the profile from command line. Seem cool? Here are the steps:
    Go ahead, and start cleanmgr.exe with the following parameters:
    cleanmgr.exe /sageset:1703

    The parameter sageset instructs the cleanup wizard to save the selected options to the registry. The following number after the parameter sets the profile ID, or number, with which the settings are stored. The Number can be from 0 to 65535, so there might be enough numbering possible.

    As soon as the wizard is loaded, you can select all the options you want to include within the cleanup, in my case, I only selected “Previous Windows Installation(s)” as shown in a print screen above. After a click on OK, the wizard writes this settings to the registry under “Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches”, per each setting:

    As you can see on the previous picture, every setting from the wizard has a corresponding key within the registry. So if you have selected “Previous Windows Installation(s)”, you will find a new entry under “Previous Installations”, in my case named “StateFlags1703”, where the number from the parameter is represented:

    Now you can export this, and import it within the Task Sequence, oder just write it through Powershell with the following command:
    New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\Previous Installations\" -Name "StateFlags1703" -Type DWORD -Value 2

    When this is done, you only need to call cleanmgr.exe with the “sagerun” parameter, and the not (?) documented silent parameter:
    cleanmgr.exe /sagerun:1703 /S
    Without the /S parameter, the GUI will show up and requires you to press OK, what will not work within a TS.

    Hope this helps, and deleting the windows.old folder, I still recommend to do only if required, otherwise let the scheduled task do the magic.

    Intune – Deploy required user settings to Windows 10 with powershell

    $
    0
    0

    In this blog I would like to describe, how I managed to set required user settings to Windows 10.
    Since I still do have an On-Premises environment, in which also File Servers reside and a DFS Namespace is still up and running, I wanted to make sure to get the advantages of using the local network.
    So here are my two use-cases to solve:
    1. Add a Network location for the DFS Path if the user is logged on On-Premises
    2. Modify the local “host” file, to redirect the workfolder clients to the file server internally

    With this goals to achieve given, it was quite clear: It’s scripting time again *happy*
    So I decided to create a single script, which I can use for both tasks. This means I need to check, if a user is running the script, or if it’s in System context. Due to the fact that the DFS link resides within the user profile, the script needs to run in user context. On the other hand the host file requires Admin permission for modifications. This is great, because within Intune, we can easily select, if the script should run in user or system context:

    My solution to check if the script is running in system or in user context is the following line (I will provide the whole script at the end):

    And the second important question is: Am I on the local network? For this, I simply check if I can reach port 389 of a known Domain Controller in my network:

    With that is set, I was able to go ahead and define the settings that should get applied.
    The first setting was creating a Network Location within Windows explorer if the domain controller is reachable, and if the DC is not reachable to remove the Link. For the creation of the Network location, I found a very nice function of Tom White on the TechNet Gallery:
    Add-NetworkLocation – A function to create an advanced network location

    Im simply took this function and implemented it in my script.
    The following section creates the link if a DC is available, or it deletes the link:

    This will cover the user settings. Now it’s up to the Host file. For modifying the host file, I have to make sure that the script is running in System Context, as it requires Administrative permission.
    For adding or removing lines to the host file, I’m using those two functions (be aware, the search string is hard-coded):

    So I then need only to trigger the correct function:

    All is done for the script (again, for better readability of the blog, I post the whole script at the end), and I can go ahead, and test the solution through Intune. Just create a PowerShell configuration twice with the same script, where you configure one script running in user context, and the other in system context. I created a Azure AD security group and added my test machine to the group, this group I then used for both PowerShell Configuration Profiles.

    And everything worked great:

    So the first step of creating a script which does the job is done. Next up would be to deploy the script to the clients, because the Intune configuration would only run the script once. I’m thinking about to create a Script, which creates two scheduled tasks, one for the user and one for the system. The scheduled tasks would then be configured to run at user logon. But I am not sure about this yet, but I’m quite sure that I will create a blog about the final solution.

    And here is the whole script:
    Function Check-DCAvailable {
    param(
    [Parameter(Position=0,mandatory=$true)][string]$DCToCheck
    )
    #Check if DC is available on LDAP
    $LDAPTestResult = $null
    $LDAPTestResult = Test-NetConnection -ComputerName $LocalDomainController -Port 389 -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
    if($LDAPTestResult.TcpTestSucceeded -ne $true) {
    Write-Host ("Domaincontroller was not answering: " + $LocalDomainController) -ForegroundColor Yellow
    return $false
    }
    else {
    return $true
    }
    }

    function Remove-HostFileWorkFolderEntry {
    $hostFile = ($env:SystemRoot + "\System32\drivers\etc\hosts")
    $hostFileContent = Get-Content -Path $hostFile
    $hostFileContent = $hostFileContent | foreach{if(($_ -like "*workfolders.hosebei.ch*") -eq $true) { Write-Host $_ } else {$_}}
    $hostFileContent | Out-File $hostFile -enc ascii

    }

    function Add-HostFileWorkFolderEntry {
    $hostFile = ($env:SystemRoot + "\System32\drivers\etc\hosts")
    $hostFileContent = Get-Content -Path $hostFile
    if(($hostFileContent -contains "workfolders.hosebei.ch") -ne $true) {
    $hostFileContent = $hostFileContent + "192.168.1.166 workfolders.hosebei.ch"

    }
    $hostFileContent | Out-File $hostFile -enc ascii

    }

    function Add-NetworkLocation

    {
    [CmdLetBinding()]
    param
    (
    [Parameter(Mandatory=$true)][string]$networkLocationPath,
    [Parameter(Mandatory=$true)][string]$networkLocationName ,
    [Parameter(Mandatory=$true)][string]$networkLocationTarget
    )
    Begin
    {
    Write-Verbose -Message "Network location path: `"$networkLocationPath`"."
    Write-Verbose -Message "Network location name: `"$networkLocationName`"."
    Write-Verbose -Message "Network location target: `"$networkLocationTarget`"."
    Set-Variable -Name desktopIniContent -Option ReadOnly -value ([string]"[.ShellClassInfo]`r`nCLSID2={0AFACED1-E828-11D1-9187-B532F1E9575D}`r`nFlags=2")
    }
    Process
    {
    Write-Verbose -Message "Checking that `"$networkLocationPath`" is a valid directory..."
    if(Test-Path -Path $networkLocationPath -PathType Container)
    {
    try
    {
    Write-Verbose -Message "Creating `"$networkLocationPath\$networkLocationName`"."
    [void]$(New-Item -Path "$networkLocationPath\$networkLocationName" -ItemType Directory -ErrorAction Stop)
    Write-Verbose -Message "Setting system attribute on `"$networkLocationPath\$networkLocationName`"."
    Set-ItemProperty -Path "$networkLocationPath\$networkLocationName" -Name Attributes -Value ([System.IO.FileAttributes]::System) -ErrorAction Stop
    }
    catch [Exception]
    {
    Write-Error -Message "Cannot create or set attributes on `"$networkLocationPath\$networkLocationName`". Check your access and/or permissions."
    return $false
    }
    }
    else
    {
    Write-Error -Message "`"$networkLocationPath`" is not a valid directory path."
    return $false
    }
    try
    {
    Write-Verbose -Message "Creating `"$networkLocationPath\$networkLocationName\desktop.ini`"."
    [object]$desktopIni = New-Item -Path "$networkLocationPath\$networkLocationName\desktop.ini" -ItemType File
    Write-Verbose -Message "Writing to `"$($desktopIni.FullName)`"."
    Add-Content -Path $desktopIni.FullName -Value $desktopIniContent
    }
    catch [Exception]
    {
    Write-Error -Message "Error while creating or writing to `"$networkLocationPath\$networkLocationName\desktop.ini`". Check your access and/or permissions."
    return $false
    }
    try
    {
    $WshShell = New-Object -ComObject WScript.Shell
    Write-Verbose -Message "Creating shortcut to `"$networkLocationTarget`" at `"$networkLocationPath\$networkLocationName\target.lnk`"."
    $Shortcut = $WshShell.CreateShortcut("$networkLocationPath\$networkLocationName\target.lnk")
    $Shortcut.TargetPath = $networkLocationTarget
    $Shortcut.Description = "Created $(Get-Date -Format s) by $($MyInvocation.MyCommand)."
    $Shortcut.Save()
    }
    catch [Exception]
    {
    Write-Error -Message "Error while creating shortcut @ `"$networkLocationPath\$networkLocationName\target.lnk`". Check your access and permissions."
    return $false
    }
    return $true
    }
    }

    #-----------------------------
    #Main Script
    #Variables
    $LocalDomainController = "hosebeidc02.deheim.hosebei.ch"

    #Determine if Script was started with system
    $bSystemContext = ([Security.Principal.WindowsIdentity]::GetCurrent()).IsSystem

    if($bSystemContext -eq $false) {
    #Execute User Section

    #Create Network Links
    if(Check-DCAvailable($LocalDomainController)) {
    #DC was found, we can assume getting a kerberos ticket for accesing SMB shares
    Write-Host ("Connecting network locations") -ForegroundColor Green

    #test if Hosebei DFSlink is existent, if not, create it
    Write-Host ("Connecting Hosebei DFS") -ForegroundColor Green
    if((Test-Path -Path "$env:APPDATA\Microsoft\Windows\Network Shortcuts\Hosebei DFS") -ne $true) {
    $null = Add-NetworkLocation -networkLocationPath "$env:APPDATA\Microsoft\Windows\Network Shortcuts" -networkLocationName "Hosebei DFS" -networkLocationTarget "\\deheim.hosebei.ch\hosebeiDFSroot"
    }
    }
    else {
    #Remove existing Links
    Write-Host ("Removing network locations") -ForegroundColor Yellow

    #test if Hosebei DFSlink is existent, if true, remove it
    Write-Host ("Remove Hosebei DFS Link due to no DC Access") -ForegroundColor Yellow
    if((Test-Path -Path "$env:APPDATA\Microsoft\Windows\Network Shortcuts\Hosebei DFS") -eq $true) {
    Remove-Item -Path "$env:APPDATA\Microsoft\Windows\Network Shortcuts\Hosebei DFS" -Force -Recurse
    }
    }
    }
    else {
    #execute system Section

    #Modify host file for Workfolder access
    #Get HostFile
    $hostFile = ($env:SystemRoot + "\System32\drivers\etc\hosts")
    $hostFileContent = Get-Content -Path $hostFile
    if(Check-DCAvailable($LocalDomainController)) {
    #DC was found, we can directly access the file server
    Add-HostFileWorkFolderEntry
    }
    else {
    #No DC was found, we need to sync workfolders through the azure ad app proxy
    Remove-HostFileWorkFolderEntry
    }
    }

    Viewing all 19 articles
    Browse latest View live


    Latest Images