What is Azure Lighthouse

Working at an MSP / CSP have taught me many things. Mainly that keeping track of credentials is a bitch. I jest, but not really. Some features of the partner dashboard that Microsoft provides makes it easier, lets you jump into a customers tenant but it’s flawed. You would have to go through the Partner Dashboard, find the customer and then select a link to whatever service you want to manage. Microsoft realized that it’s a struggle and have created Azure Lighthouse, a cross-customer management solution. The service itself is free, but if you use other services with it you have to pay for those, obviously.

What you get in Azure Lighthouse <figcaption>What you get in Azure Lighthouse</figcaption></figure>

With Azure Lighthouse, any management service provider will be able to have one view of their entire customer base. Monitoring, compliance and security, all in one portal. This makes working with customers so much better, and eventually, make the experience better for end users.

I recommend reading up on the service on the Azure Lighthouse product page, but also take a look at this demonstration video.

read more

Using PowerShell to gather information from XML

Making a long backstory short, I was checking one of our local weather sites during one of the few warm summer days here in Northern-Norway. For most people, it ends there but I obviously started thinking that it would be so much easier to write a function that could check the weather for me. I head off to check their API and it turns out that they are working on a modern API but is serving out XML files based on location.

I have never worked with XML before, so the journey to extract the information I wanted was kind of interesting. I noted everything, so let’s take a look at how one can go about extracting the information one needs from XML and use it in PowerShell. Feel free to follow the lines of code.

Turns out my example Yr (a weather service in Norway) has changed a lot in it’s XML structure. The example still applies, but I’ll update this as soon as possible with new example data.

# Load the file, define it as XML.
$URL = "https://www.yr.no/sted/Norge/postnummer/9024/varsel.xml"
[xml]$file = Invoke-webrequest -uri $URL
# Check the result.
$file
# Check the property "weatherdata".
$file.weatherdata
# We want real time data, so let's continue with observations.
$file.weatherdata.observations
# Closing in at something. Checking out our options by using Get-Member...
$file.weatherdata.observations | Get-Member
# And now, weatherstation?
$file.weatherdata.observations.weatherstation
# Bingo.

read more

PowerShell Monthly, June 2019

Blog Articles

An Example Azure DevOps Release Pipeline for PowerShell modules
https://adamrushuk.github.io/example-azure-devops-release-pipeline-for-powershell-modules/

Configuring Power Scheme with a PowerShell One-Liner
https://mickitblog.blogspot.com/2019/06/configuring-power-scheme-with.html

Create and Import Autopilot CSV File into Intune from OOBE
https://nedimmehic.org/2019/06/05/create-and-import-autopilot-csv-file-into-intune-from-oobe/

Export-CliXML and Import-CliXML serialization woes
https://evotec.xyz/export-clixml-and-import-clixml-serialization-woes/

Fixing Active Directory PasswordNotRequired with PowerShell
https://evotec.xyz/fixing-active-directory-passwordnotrequired-with-powershell/

Getting Windows 10 build version from Active Directory
https://evotec.xyz/getting-windows-10-build-version-from-active-directory/

Iron Scripter challenge: A PowerShell Cryptogram
https://ironscripter.us/a-powershell-cryptogram/

Locking Down PowerShell to Foil Attackers: 3 Essentials
https://www.bankinfosecurity.com/locking-down-powershell-to-foil-attackers-a-10662

PowerShell 7 gets new core, simplified credentials, logging
https://devclass.com/2019/06/03/powershell-7-gets-new-core-simplified-credentials-logging/

PowerShell Script to Delete Files By Age with Email Summary Report and MS Teams Notification
https://www.lazyexchangeadmin.com/2019/05/Delete-FilesByAge.ps1.html

Restore Group Policy with PowerShell
https://4sysops.com/archives/restore-group-policy-with-powershell/

SharePoint servers report using PowerShell
https://gallery.technet.microsoft.com/office/Get-colorful-server-report-cc92e38b

Using PowerShell to retrieve CAC Information
https://sccmf12twice.com/2019/06/using-powershell-to-retrieve-cac-information/

read more

Working with Windows Registry and PowerShell

Most people that does system administration in a Windows environment have had to work with the Windows Registry. This registry serves as a database of settings, used with everything from applications to drivers. The usual way of working with the Windows Registry is through regedit or Group Policy Objects but what if you have a server core that is not domain joined?

As per usual, PowerShell to the rescue!

How does it work

One magical thing about PowerShell is the concept of PowerShell Drives (PSDrives) which works with a PowerShell Provider to make it easy to use data stores in PowerShell. One example is your C-drive, which is available as a PSDrive through the FileSystem provider. There are several other providers that are mapped through PSDrives, like WSMan, Alias, Certificate and more importantly for this article the Registry-provider.

By using the drives HKLM: and HKCU: you can browse the registry, as if it was folders on your computer. Combined with the fact that a registry key is an item, you could then either add a new registry keys or add / change registry entries by changing the properties on said keys.

Example

# List registry items
Get-ChildItem HKCU:
# List registry items, selecting just the name of the item
Get-ChildItem HKCU: | Select-Object Name
# List registry items, recursively 
Get-ChildItem HKCU: -Recurse

Creating new items and changing their property

# Create the item
New-Item HKCU:\Environment\Test
# Create a DWORD, set it to 1
Set-ItemProperty -Path HKCU:\Environment\test\ -Name "dword" -Value "1" -Type DWord
# List all values 
Get-ItemProperty -Path HKCU:\Environment\test\

You can see a lot more examples at the Microsoft documentations.

read more

Cross-Forest mailbox migration with Microsoft Exchange

We recently started a fun project, doing some mailbox migration. For this project, in particular, we were merging four Exchange organizations together and the new Active Directory was to consist of brand new user accounts. In other words, we’re not moving the accounts themselves but just the mailbox.

The solution was a mixture of what docs.microsoft.com and many of the articles that I had read, so my thinking is that there’s a need for a really explicit article about this process. As always I use PowerShell wherever it’s applicable and we will specifically be looking at how we can migrate mailbox to a forest where the users already exist.

Mailbox migration process </figure>

Prerequisite for cross-forest mailbox migration

There are a few things that need to be done before performing a cross-forest mailbox migration. Some are mandatory, others option or just nice to have done.

Run the latest patch of your Exchange server: Whenever I talk to customers about mailbox migration, I ask them to upgrade to the latest cumulative update. In some cases, it’s a necessity but either way, it should be done, just to make sure you don’t end up catching any bugs during the migration.

Have the right permissions: You can migrate mailboxes if you’re part of the Organization Management or the Recipient Management role group. Remember to practice the rule of least privilege.

Enable MRS Proxy endpoint: This is required for any cross-forest mailbox migration or remote move migrations between on-premises and Exchange Online. You could enable this either through EAC or with PowerShell.

If migrating mailboxes to existing users, they have to be mail enabled: So that the mailbox will match up, you have to run Enable-MailUser with the ExternalEmailAddress parameter.

The Exchange organizations should be connected: This one might be obvious, but it’s still worth mentioning. You need to be able to connect to EWS to migrate mailboxes.

Prepare for the mailbox migration

Preparing the mailbox is really a simple step. We utilize a script that comes with Exchange and then update the recipient. The script then copies some vital attributes from the source mailbox user to the target mail user. The following will be copied:

  • msExchMailboxGUID
  • msExchArchiveGUID
  • msExchArchiveName

Supposedly, the script should run the cmdlet Update-Recipient. This is to add the LegacyExchangeDN attribute to the user but this has not yet happened to me. Just in case it doesn’t happen, we will do this at the end of the script.

As you will see, we use the UseLocalObject and OverWriteLocalObject to merge the information of the mailbox to our existing user.

# Change directory to the script folder
CD "C:\Program Files\Microsoft\Exchange server\V15\Scripts"

# Add credentials, from both forests
## Remote = Source forest (Where the mailbox resides)
## Local  = Target forest (Where your new user is)

$RemoteCreds = Get-Credential
$LocalCreds = Get-Credential

# Create a splat with all our parameters and switches
$splat = @{
   identity = "[email protected]"
   RemoteForestDomainController = "dc1.old.domain.org"
   RemoteForestCredential = $RemoteCreds
   LocalForestDomainController = "dc1.new.domain.org"
   localForestCredential = $LocalCreds
   UseLocalObject = $True
   OverWriteLocalObject = $true
}

# Run the script, with our splat
.\Prepare-MoveRequest.ps1 @splat

# Make sure that the LegacyExchangeDN is added
Update-Recipient [email protected]

PowerShell will let us know that the command is done running and that your mailbox is ready to be migrated.

If you’re migrating more than one mailbox you could either pipe several users or use a CSV. In either case, remember to remove the identity parameter in your splat.

If you’re curious about splatting, feel free to read this short introduction I’ve written.

Start the mailbox migration

We will start off by defining what Exchange-server we are migrating from, and what the new

$splat = @{
   Identity = "[email protected]"
   Remote = $True
   RemoteHostName = "exchange.old.domain.org"
   RemoteCredential = $RemoteCreds
   TargetDeliveryDomain = "new.domain.org"
}

New-MoveRequest @splat

You should now have created a new request that will migrate the users mailbox between forests, from one Exchange organization to another.

read more