Blog

  • Saving Attachments using Power Automate

    You can use Power Automate to save incoming email attachments to OneDrive or SharePoint.

    This is the flow we are going to create, in this example it saves to OneDrive.

    The settings for When a new email arrives:

    In my example I am only going to process emails that have the word “Quote” in the subject.

    The Foreach settings are:

    The Condition filters to only process pdfs.

    Lastly the true condition:

    Note when selecting the File content it will appear as Attachments Content.

  • Changing incorrectly named Tenant in M365 partner portal

    Note – this method no longer works. Sorry.

    We had a couple of incorrectly named tenants in our partner portal. The name was correct for everything on the tenant’s side, only wrong on the partner portal.

    A helpful MS support agent sent me this which sorted it out.

        •    SymptomChange Customer display name on Partner Center portal

        •    Resolution

    • We informed you that the contract entity is made at the time of establishing the reseller relationship with your end customer.
    • This entity contracts have attributes like displayName, defaultDomainName etc. which is not automatically updated if the customer tenant’s attributes gets change.
    • However, using the graph explorer we made the changes in the display name of the customer in the partner center portal. This can also be used to make changes to the domain name present in the agreement. This contract entity can be accessed/modified using the graph API and below are the steps for future reference:
    1. Log into https://graphexplorer.azurewebsites.net/ using your partner Global Admin credentials.
    2. Get the list of the Partner Contacts using the following REST Call mentioned in (a) else if you have high list of customers, you can make use of filters in the endpoint URL(b).
    1. GET https://graph.windows.net/myorganization/contracts?api-version=1.6
    2. GET https://graph.windows.net/myorganization/contracts?$filter=startswith(defaultDomainName,'<new domain name>’)
    3. Copy the Object ID of the customer that you wanted to change the Company name/domain name
    4. Use the following REST call to update the attributes of the contract entity:
    1. PATCH https://graph.windows.net/myorganization/contracts/<object-id-of-contract>?api-version=1.6
    2. Used the following JSON body as parameter:-

    {

    “displayName”:”New name”

    }

    • Post following the steps, we were successfully able to change the display name of the customer on Partner Center portal
  • Using Secure Model Authentication to manage Azure AD on multiple tenants

    I set myself what I thought would be a simple automation task today. I want to start syncing our clients Azure AD to Autotask to automatically create contacts. Will save an extra step when we onboard a new client or user.

    To do this we have to do two things, register an app in the clients Azure AD, and grab the ID of a group that contains all the users you want to sync.

    To simplify this I thought I’d use PowerShell to create a Dynamic Group on each tenancy with the same name, with a rule in it to to include all active licenced users, and grab its ID along with the clients tenant name into a CSV. Then when I need it I can just copy and paste it.

    Turns out that is a little more awkward than I thought. First issue is that creating Dynamic Groups using the New-AzureADMSGroup is still a preview feature, so I needed to run:

    Remove-Module
    Import-Module AzureADPreview

    Next I had to generate the application secret and keys on our tenancy to authenticate as a partner. I did that using Kelvin Tegelaar’s script: Connect to Exchange Online automated when MFA is enabled (Using the SecureApp Model) – CyberDrain

    Running this and following all its authentication prompts generates the authentication keys you need. Keep them safe!

    Next I grabbed the script from here: Re: Exchange Online and the Secure App Model – Page 2 – Microsoft Partner Community that put it all together, and came up with my final script.

    Note that dynamic groups only work if the client has Azure AD P1 or higher, and it turned out that far fewer of my clients have it than I thought!

    remove-module azuread
    import-module AzureADPreview 
    $ApplicationId         = 'Paste Application ID here as from CyberDrain Script'
    $ApplicationSecret     = 'Paste Application Secret here as from CyberDrain Script' | Convertto-SecureString -AsPlainText -Force
    $TenantID              = 'Your (Partners) Tenant ID'
    $Upn = 'Your email address'
    
    $RefreshToken          = 'Paste Refresh Token here as from CyberDrain Script (it will be very long)'
    $ExchangeRefreshToken  = 'Paste Refresh Token here as from CyberDrain Script (it will be very long)'
    
    # CSP Partner connection:
    $credential = New-Object System.Management.Automation.PSCredential($ApplicationId, $ApplicationSecret)
    
    $aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID 
    $graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID 
    
    Connect-AzureAD -AadAccessToken $aadGraphToken.AccessToken -AccountId $Upn -MsAccessToken $graphToken.AccessToken -TenantId $tenantID
    
    # Find all your Customers/Clients
    $Customers = Get-AzureADContract -All $True | select DefaultDomainName, CustomerContextID
    # Disconnect from your AzureAD
    Disconnect-AzureAD
    
    #Loop through each tenant
    foreach($customer in $Customers){
    
    #Connect to the tenant
    $CustAadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $Customer.CustomerContextId
    $CustGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $Customer.CustomerContextId
    # Connect to Tenant's Azure AD
    Connect-AzureAD -AadAccessToken $CustAadGraphToken.AccessToken -AccountId $upn -MsAccessToken $CustGraphToken.AccessToken -TenantId $customer.CustomerContextId
    
    # Create Dynamic group
    New-AzureADMSGroup -DisplayName "Azure AD Sync" -Description "Dynamic group for Syncing to Autotask" -MailEnabled $false -MailNickName "group" -SecurityEnabled $true -GroupTypes "DynamicMembership"  -MembershipRuleProcessingState "On" -MembershipRule "(user.accountEnabled -eq True) and (user.objectId -ne null) and (user.userType -eq ""Member"") and not (user.assignedPlans -all (assignedPlan.servicePlanId -eq """"))"
    
    $groupresult = get-azureadmsgroup -SearchString "Azure Ad Sync"
    
    #Write Tenant's Domain name and the Group ID to a CSV
    Add-Content -Path .\Groups.csv -Value "$($customer.DefaultDomainName), $($groupresult.id)"
    
    #Screen output so you know it is doing something!
    write-host $customer.DefaultDomainName, $groupresult.id, " Tenant ID ", $customer.CustomerContextId
    # Then: Disconnect-AzureAD  when done with each Customer, unless also connecting to ExchOnline
    Disconnect-AzureAD
    
    }
    
    
    
    
    
    

    My next step may be to generate the application and write out the apps ID and secret for importing to Autotask.

  • Microsoft/Office 365 rename

    Going live tomorrow (21st April 2020) Microsoft are renaming some of the Office 365 and Microsoft 365 products. I guess this is what happens when the marketing department have too much time on their hands.

    They are renaming all the Business Office 365 range into a Microsoft 365 naming convention.

    https://www.microsoft.com/en-gb/microsoft-365/blog/2020/03/30/new-microsoft-365-offerings-small-and-medium-sized-businesses/

    Office 365 Business Essentialsis nowMicrosoft 365 Business Basic
    Office 365 Business Premiumis nowMicrosoft 365 Business Standard
    Microsoft 365 Businessis nowMicrosoft 365 Business Premium
    Office 365 Businessis nowMicrosoft 365 Apps for business
    Office 365 ProPlusis nowMicrosoft 365 Apps for enterprise
    https://www.microsoft.com/en-us/microsoft-365/blog/2020/03/30/new-microsoft-365-offerings-small-and-medium-sized-businesses/
  • Microsoft Teams Background

    Microsoft have launched an update to Teams that allows you to change your background. But what if you don’t want to use one of their preinstalled images?

    Simply copy the image of your choice to:

    %appdata%\Microsoft\Teams\Backgrounds\Uploads

    And it will be available to choose.

    If % appdata% doesn’t work then it will be something like:

    C:\Users\adam\AppData\Roaming\Microsoft\Teams\Backgrounds\Uploads

    Now you can appear in lockdown meetings as if you are at your favourite place.

    Some of the Shadowfax Team having a Microsoft Teams meeting.
  • Secure passwords

    Setting a decent password policy has long been a none of contention. IT people want passwords to be secure, and users want something that they can remember.

    Net result is that a lot of password policies force users to use something that is hard to remember, but comparatively easy to crack. Having hard to remember passwords leads to users writing them down, reusing them in multiple places, or just coming up with something like P@ssw0rd and thinking they have bucked the system.

    XCD wrote a cartoon about it:

    https://xkcd.com/936/

    So, to help out at Shadowfax I’ve created a password generator for our website. It is nice and simple, generates a password based on a number of random words (I recommend three). There are then options for whether you need a number, capital letter and symbol.

    I also added an option to let you set the maximum size of the words used. The dictionary I’m using has 86,000 words in it, and I’ve found if you leave it too long it suggests words above my vocabulary. Great for learning new words- but hard to remember!

    https://sfax.co.uk/pwd

  • What is my IP Address?

    I got fed up with using other people’s pages to check public IP addresses, so have put our own checker on our main website:

    https://sfax.co.uk/ip

    Google will tell you your IP address if you google “what is my ip address” but when you are on unfamiliar systems you may find the default search engine is Bing or something stupid like that.

    So now I have a nice quick url to look it up on.

  • Deleting files over a certain age

    We sometimes find the need to delete all files from a folder over a certain age. For example we have a folder that our network scanner dumps its scans in. Ideally everyone would file their scans straight away, but it doesn’t always happen.

    So we have the following script running every hour that removes all files from the folder that are over an hour old.

    Get-ChildItem –Path "C:\scans" -Recurse | Where-Object {($_.LastWriteTime -lt (Get-Date).AddMinutes(-60))} | Remove-Item

    You can change .AddMinutes to .AddHours, .AddDays or AddMonths as appropriate.

  • Syncing Windows Time service to an external source

    It is important to have the Windows Time Service on a DC on the network pointing to an external NTP source to keep time in sync.

    There is an article here which tells you how:

    https://support.microsoft.com/en-us/help/816042/how-to-configure-an-authoritative-time-server-in-windows-server

    I’ve condensed it here to a reg file you can create and run.

    Copy the following code into a text document, name it time.reg and run it on a DC.

    Then restart the time service with the command:

    net stop w32time && net start w32time

    Give it a few seconds and the clock should correct itself.

    If it is a virtual machine make sure that the Hyper Visor isn’t pushing time out to it, as the server will take that as priority. For example on Hyper-V go to the VM Settings, and Integration Services and un-tick Time synchronization.

    The registry file

    Windows Registry Editor Version 5.00

    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer]
    “Enabled”=dword:00000001
    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Parameters]
    “NtpServer”=”0.europe.pool.ntp.org,0x1 1.europe.pool.ntp.org”
    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient\SpecialPollInterval]
    “SpecialPollInterval”=dword:900
    [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config]
    “MaxPosPhaseCorrection”=dword:00000e10
    “MaxNegativePhaseCorrection”=dword:00000e10

     

  • Migrating from NTFRS to DFSR replication of Sysvol

    DFSR replication of sysvol is much more reliable, and NTFRS is being deprecated after Windows Server 2016.

    This is how to migrate to DFSR. The information here is gleamed from :

    https://blogs.technet.microsoft.com/filecab/2014/06/25/streamlined-migration-of-frs-to-dfsr-sysvol/

    and the long version:

    https://technet.microsoft.com/en-us/library/dd640019%28v=WS.10%29.aspx?f=255&MSPPError=-2147217396

    Check forest functional level using domain.msc and raise if below 2008.

    Force a replication with:

    Repadmin /syncall /force /APed

    this is optional, but will speed things up, and you can use this replication to check for errors.

    Check event log for errors, especially the File Replication Service logs.

    Repadmin /replsummary

    Check that replication is working.

    Dcdiag /e /test:sysvolcheck /test:advertising

    Fix any errors.

    Next the migration.

    dfsrmig /setglobalstate 1

    Run

    dfsrmig /getmigrationstate

    Do not proceed further until it tells you that “All domain controllers have migrated successfully to the Global state.”

    dfsrmig /setglobalstate 2

    Again check it with

    dfsrmig /getmigrationstate

    And make sure all DCs have migrated.

    Finally

    dfsrmig /setglobalstate 3

    And it is finished when

    dfsrmig /getglobalstate

    tells you that all DCs have migrated successfully.

    You can apparently go straight to state 3, but it doesn’t take long to go the full route, so better taking a little time.