Author Archives: Daniel G

What is Azure DNS? And how do I get started?

One of the new Azure services announced at Ignite was Azure DNS. A globally replicated and highly available DNS service leveraging Anycast for fast DNS responses from anywhere around the globe. Wow. Since it’s using well known management tools (Powershell) and integration interfaces (REST and C#) Azure DNS is really easy to build upon and maximize on the investment.

The only thing I’m missing (for obvious reasons) is the ability to register and manage domains at a registrar level. Hopefully a <insert domain registrar name here> Resource Provider is only a matter of time.

I’m very excited about this since I am wasting was wasting a boatload of money on two A0 VMs in an availability set hosting DNS. Since I had a small boat it only fit about $30/month.. 😉
With Azure DNS I’m only paying $0.25 per zone and $0.20 per 1 billion queries. So I basically cut my DNS cost by 99% and reduced my management cost by about the same amount.

Gettings started with Azure DNS

To sign up for Azure DNS, which is currently in preview, you’ll have to use Powershell. Be sure you have at least version 0.9.1 installed. Even tho DNS Cmdlets have been hiding since November 26th, 2014.
You easily can download and install the latest version with the help of this post.

Add-AzureAccount
Switch-AzureMode -Name AzureResourceManager
# Had to re-register the Microsoft.Network provider for the DNS feature to ever become Registered
Register-AzureProvider -ProviderNamespace Microsoft.Network
Register-AzureProviderFeature -ProviderNamespace Microsoft.Network -FeatureName azurednspreview

Wait until RegistrationState turns into Registered. It should happen almost instantly.

Get-AzureProviderFeature -ProviderNamespace Microsoft.Network -FeatureName azurednspreview | fl *

FeatureName : azurednspreview
ProviderName : Microsoft.Network
RegistrationState : Registered

Next we’ll create our first DNS Zone. All zones must be placed inside a Resource Group.

New-AzureResourceGroup -Name WE-DMZ-DNS -Location westeurope
New-AzureDnsZone -Name runbookautomation.se -ResourceGroupName WE-DMZ-DNS
# Get DNS zone name server
(Get-AzureDnsRecordSet -ZoneName runbookautomation.se -ResourceGroupName WE-DMZ-DNS -Name '@' -RecordType NS).Records

Next up is the slow and tricky part. The last row in the previous snippet expands the name servers of your newly created zone. These name servers need to be configured at your domain registrar.

This is how it looked like at my registrar:
binerodns

Once the DNS changes have replicated and Resolve-DnsName returns something like this you are good to go. The key property here is PrimaryServer.
resolvedns

Lastly we’ll create a CNAME record:

# Get the target Zone
$Zone = Get-AzureDnsZone -Name runbookautomation.se -ResourceGroupName WE-DMZ-DNS
# Create the DNS Record Set
$RecordSet = New-AzureDnsRecordSet -Name blog -RecordType CNAME -Ttl 3600 -Zone $Zone
# Add the CNAME value to the DNS Record Set
Add-AzureDnsRecordConfig -RecordSet $RecordSet -Cname blog-runbookautomation-se.azurewebsites.net
# Apply changes to Record Set in Azure
Set-AzureDnsRecordSet -RecordSet $RecordSet

Below is the complete code using variables for easier use.

Update Azure Powershell module with Powershell

A couple of months ago I shared a script that downloaded and installed the latest version of the Azure Powershell module. Since that time a lot of things have changed.

The module has moved from azure-sdk-tools to azure-powershell on GitHub!
The module has been updated from version 0.8.6 to version 0.9.1 with the help of over 3000 commits!
The module has gone from 434 cmdlets up to 761 cmdlets!

Below is a new snippet that leverages the GitHub API to download and install the latest Azure Powershell module:

Download and invoke the script to update. Or just run this one-liner:

Getting an accurate last logon date of Active Directory users

Sometimes the LastLogonTimeStamp attribute just doesn’t cut it and other times LastLogon just isn’t accurate on the Domain Controller you’re querying.

This attribute is not replicated and is maintained separately on each domain controller in the domain. To get an accurate value for the user’s last logon in the domain, the Last-Logon attribute for the user must be retrieved from every domain controller in the domain. The largest value that is retrieved is the true last logon time for that user.

Manually checking each DC and determinating the largest datetime value of LastLogon is clearly out the question so we’ll use Powershell instead!

To maintain as much flexibility as possible, ease of use and respect already established methods of working against AD with Powershell I’ve created a function that allows pipeline input from Get-ADUser and SamAccountName arrays (read: Import-CSV and Get-Content).

Per usual you’ll find the script at TechNet Gallery!

<#
.Synopsis
   Gets the newest LastLogon date based on data from all Domain Controllers in the Forest.
.DESCRIPTION
   Get the newest LastLogon attribute for the specified user by iterating through all Domain Controllers in the forest.
   Output is structured and enables sorting, CSV export and further processing.
.EXAMPLE
    # Get LastLogon date for one username:
    C:\PS> Get-ADUserLastLogon -SamAccountName username

    DomainController : dc01.contoso.com
    Enabled          : True
    Name             : User Name
    SamAccountName   : username
    LastLogon        : 2015-03-30 15:11:06

.EXAMPLE
    # Get LastLogon date for multiple usernames and output as table:
    C:\PS> "username","nameuser" | Get-ADUserLastLogon | Format-Table -AutoSize

    DomainController     Enabled Name        SamAccountName LastLogon
    ----------------     ------- ----        -------------- ---------
    dc01.contoso.com        True User Name   username       2015-03-30 15:11:06
    dc02.contoso.com        True Name User   nameuser       2015-03-30 13:58:38
.EXAMPLE
    # Get LastLogon date for all users under an Organizational Unit:
    C:\PS> $OU = "OU=ServiceAccounts,DC=contoso,DC=com"
    C:\PS> $ADUsers = Get-ADUsers -Filter * -SearchBase $OU
    C:\PS> $ADUsers | Get-ADUserLastLogon -Properties Title
.EXAMPLE
    # Get LastLogon date for the first 50 users of a remote forest and remote credentials:
    C:\PS> $Cred = Get-Credential
    C:\PS> Get-ADUserLastLogon -All -Count 50 -Forest contoso.org -Credential $Cred
.EXAMPLE
    # Get LastLogon date for the first 5 users and output the AD User object of the first users:
    C:\PS> $Result = Get-ADUserLastLogon -All -Count 5 -Passthru
    C:\PS> $Result[0].TargetObject
.INPUTS
   [System.String]
   [Microsoft.ActiveDirectory.Management.ADUser]
.OUTPUTS
   [System.Management.Automation.PSObject]
.PARAMETER SamAccountName
    Account name, as a string, to get LastLogon date.
.PARAMETER ADUser
    Account, from Get-ADUser cmdlet, to get LastLogon date.
.PARAMETER All
    Gets all AD users of the specified domain.
    Use together with -Count parameter to restrict amount of results.
.PARAMETER Count
    Max amount of results when using -All parameter.
.PARAMETER Forest
    Name of the remote forest. Needs to be resolvable.
.PARAMETER Properties
    Adds AD attributes to the output.
.PARAMETER Passthru
    Adds the Get-ADUser cmdlet output object into the TargetObject property.
.PARAMETER Credential
    Credentials to use with Get-ADUser and/or connecting to a remote forest.
.NOTES
    Version: 20150330.1
    Author: Daniel Grenemark
    Email: daniel@grenemark.se
    Twitter: @desek
    Blog: https://runbookautomation.wordpress.com/
.LINK
    https://runbookautomation.wordpress.com
    https://twitter.com/desek
#>

TechNet Gallery URL: https://gallery.technet.microsoft.com/Get-AD-User-Last-Logon-4c6b6fa6

Publishing SCSM Request Offerings like an engineer!

Ever had the great idea that you’d create an enumeration list that you’ll use on several RO’s to maximize data quality and ensure successful automation?

I’ve had it. Several times in fact.

However, for obvious reasons I don’t want to relate this enumeration to any class. I want it to be stand-alone and only be used with one or several RO(s). As all “centrally managed lists” I want a change in the list to reflect on all RO(s). And as most of you know you have to map every prompt to a property of a class that is defined in the template related to the RO to be able to publish it.
There’s actually a requirement for this on the data layer and not just in the GUI, which I tought at first.

So how do you map an enumeration that is not a property of any class?

Since all configuration of RO’s are saved in a Management Pack and in XML format we should start by reading the Management Pack XML Schema Reference.
After a few clicks we should notice that the <Extension> element (which contains the RO definition) isn’t documented on MSDN. Thank you very much! Continue reading

Working with schedules in Azure Automation (and SMA)

The few of us that have started working with Azure Automation and/or SMA have probably noticed the lack of functionality that would equal a monitoring activity in Orchestrator.

I’ve seen some solutions which consist of a Runbook being set in an infinite loop with a sleep timer at the bottom.
In practice this method would replicated the desired functionality, that is, until the Runbook hits the maximum runtime value and kills the process. If you’re using Azure Automation this would also mean that you’ll be consuming Automation Minutes. 24/7.

What you’ll want to do with Azure Automation and SMA is to work with schedules to mimic a monitoring activity. And this can be a hassle to manage… Unless you’re using the right tools! 🙂
(Hint: Powershell.)

First we’ll want to create the required schedules. In 99% of the cases I work with hourly schedules at different minute intervals and I create them with the following script found at Technet Gallery.

If you use the “-Verbose” parameter you’ll get output on the schedule creation process.

And lastly we’ll want to assign Runbooks to the required schedules so the Runbook executes at the right time with the following script:

By piping to “Out-Gridview -Passthru” I can easily filter all the schedules and select the ones I want. Oh, and they script writes the intervals into the Description property of the schedules. This makes life a bit easier if you want the Runbook to execute, for example, every 5 minutes.

AaSchedules

The result would look something like this in the Azure Management Portal:

AaSetSchedules

I hope this helps you to manage your Automation Runbooks in a more efficient way and lower your Azure bill!

Again, the script can be found at: https://gallery.technet.microsoft.com/Generate-Azure-Automation-1dab9193

Cleaning up Management Pack XML after SCSM Authoring Tool

For those of you working with System Center Service Manager (SCSM) and have created or edited forms in the Authoring Tool have probably noticed that Management Pack can easily become a couple of hundred rows! And that’s just the inside the <Forms> node!

This is happening due to the fact that the Authoring Tool is basically writing 3 lines of XML for every change you make. This includes changing values, moving controls etc.

There’s also some rumors that the excess amount of rows causes performance issues when loading the form in SCSM. It sounds reasonable to me, but I haven’t personally done any testing in this matter.

But fear not! The below script will remove the unnecessary XML!

I’ve included functionality for piping several XML-files, ie.

Get-ChildItem *.xml | Invoke-SCSMAuthoringToolCleanup

You can define where to save the processed XML with the parameter -OutputPath. If omitting this parameter the script will overwrite the existing Management Pack.

If you want the XML object as output for further processing, use the parameter -Passthru.

If you’re using fixed position and control sizes (which you shouldn’t!) you can omit processing of these nodes by setting the parameters -ProcessResize and -ProcessMove to $false.

You can download the script from TechNet Gallery at:
https://gallery.technet.microsoft.com/SCSM-Form-Customization-8ebe8dd7

Workaround for SMA Runbook build failure

Building a robust master SMA Runbook for your automation solutions will have a high chance of ending up with at least a couple of hundreds of lines of code (and magic!). This runbook will most likely consist of runbook nesting, modular workflows, error-handling and fault tolerance which can make things quite complex. Even for the Powershell Engine itself..

One master Runbook I authored ran into a Workflow compilation error when executing the runbook. This because of the sandboxing technology used in SMA and the error appeared because the sandboxed instance could not find the required assemblies.

The workaround is simple;

Identify and find the missing assemblies, which I did at:

C:\WINDOWS\Microsoft.NET\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
C:\WINDOWS\Microsoft.NET\assembly\GAC_MSIL\Microsoft.PowerShell.Commands.Utility\v4.0_3.0.0.0__31bf3856ad364e35\Microsoft.PowerShell.Commands.Utility.dll

And copy them to on all SMA Runbook Workers:

%windir%\System32\WindowsPowershell\v1.0

 

Below is the complete error message found in the Event Log on the SMA Runbook Worker:


Build started 2014-10-16 13:06:31.
__________________________________________________
Project "C:\Users\<SMARunbookWorkerAccount>\AppData\Local\Temp\PSWorkflowCompilation\Workflow_f8de811dc1ff4612b48fe9cc0c69d546\Project\RuntimeProject.csproj" (default targets):

Target GetReferenceAssemblyPaths:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(983,5): warning MSB3644: The reference assemblies for framework ".NETFramework,Version=v4.5" were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend.
Done building target "GetReferenceAssemblyPaths" in project "RuntimeProject.csproj".
Target PrepareForBuild:
Creating directory "bin\Release\".
Creating directory "obj\Release\".
Target ResolveAssemblyReferences:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3106: Assembly strong name "C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell.Commands.Utility.dll" is either a path which could not be found or it is a full assembly name which is badly formed. If it is a full assembly name it may contain characters that need to be escaped with backslash(\). Those characters are Equals(=), Comma(,), Quote("), Apostrophe('), Backslash(\).
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3106: Assembly strong name "C:\Windows\System32\WindowsPowerShell\v1.0\System.Management.Automation.dll" is either a path which could not be found or it is a full assembly name which is badly formed. If it is a full assembly name it may contain characters that need to be escaped with backslash(\). Those characters are Equals(=), Comma(,), Quote("), Apostrophe('), Backslash(\).
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3106: Assembly strong name "C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell.Commands.Utility.dll" is either a path which could not be found or it is a full assembly name which is badly formed. If it is a full assembly name it may contain characters that need to be escaped with backslash(\). Those characters are Equals(=), Comma(,), Quote("), Apostrophe('), Backslash(\).
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3106: Assembly strong name "C:\Windows\System32\WindowsPowerShell\v1.0\System.Management.Automation.dll" is either a path which could not be found or it is a full assembly name which is badly formed. If it is a full assembly name it may contain characters that need to be escaped with backslash(\). Those characters are Equals(=), Comma(,), Quote("), Apostrophe('), Backslash(\).
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3270: There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "mscorlib", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3270: There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "System.Data", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.
Done building target "ResolveAssemblyReferences" in project "RuntimeProject.csproj".
Target XamlMarkupCompilePass1:
C:\Users\<SMARunbookWorkerAccount>\AppData\Local\Temp\PSWorkflowCompilation\Workflow_f8de811dc1ff4612b48fe9cc0c69d546\Project\ho5coutk.gts.xaml : error XC1014: Assembly 'Microsoft.PowerShell.Commands.Utility, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' can not be resolved. Please add a reference to this assembly in the project that is being built.
C:\Users\<SMARunbookWorkerAccount>\AppData\Local\Temp\PSWorkflowCompilation\Workflow_f8de811dc1ff4612b48fe9cc0c69d546\Project\onhtvslm.qxx.xaml : error XC1014: Assembly 'Microsoft.PowerShell.Commands.Utility, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' can not be resolved. Please add a reference to this assembly in the project that is being built.
C:\Users\<SMARunbookWorkerAccount>\AppData\Local\Temp\PSWorkflowCompilation\Workflow_f8de811dc1ff4612b48fe9cc0c69d546\Project\rl5vmykt.eca.xaml : error XC1014: Assembly 'Microsoft.PowerShell.Commands.Utility, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' can not be resolved. Please add a reference to this assembly in the project that is being built.
Done building target "XamlMarkupCompilePass1" in project "RuntimeProject.csproj" -- FAILED.

Done building project "RuntimeProject.csproj" -- FAILED.

Build FAILED.

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(983,5): warning MSB3644: The reference assemblies for framework ".NETFramework,Version=v4.5" were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend.
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3106: Assembly strong name "C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell.Commands.Utility.dll" is either a path which could not be found or it is a full assembly name which is badly formed. If it is a full assembly name it may contain characters that need to be escaped with backslash(\). Those characters are Equals(=), Comma(,), Quote("), Apostrophe('), Backslash(\).
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3106: Assembly strong name "C:\Windows\System32\WindowsPowerShell\v1.0\System.Management.Automation.dll" is either a path which could not be found or it is a full assembly name which is badly formed. If it is a full assembly name it may contain characters that need to be escaped with backslash(\). Those characters are Equals(=), Comma(,), Quote("), Apostrophe('), Backslash(\).
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3106: Assembly strong name "C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell.Commands.Utility.dll" is either a path which could not be found or it is a full assembly name which is badly formed. If it is a full assembly name it may contain characters that need to be escaped with backslash(\). Those characters are Equals(=), Comma(,), Quote("), Apostrophe('), Backslash(\).
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3106: Assembly strong name "C:\Windows\System32\WindowsPowerShell\v1.0\System.Management.Automation.dll" is either a path which could not be found or it is a full assembly name which is badly formed. If it is a full assembly name it may contain characters that need to be escaped with backslash(\). Those characters are Equals(=), Comma(,), Quote("), Apostrophe('), Backslash(\).
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3270: There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "mscorlib", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3270: There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "System.Data", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.
C:\Users\<SMARunbookWorkerAccount>\AppData\Local\Temp\PSWorkflowCompilation\Workflow_f8de811dc1ff4612b48fe9cc0c69d546\Project\ho5coutk.gts.xaml : error XC1014: Assembly 'Microsoft.PowerShell.Commands.Utility, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' can not be resolved. Please add a reference to this assembly in the project that is being built.
C:\Users\<SMARunbookWorkerAccount>\AppData\Local\Temp\PSWorkflowCompilation\Workflow_f8de811dc1ff4612b48fe9cc0c69d546\Project\onhtvslm.qxx.xaml : error XC1014: Assembly 'Microsoft.PowerShell.Commands.Utility, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' can not be resolved. Please add a reference to this assembly in the project that is being built.
C:\Users\<SMARunbookWorkerAccount>\AppData\Local\Temp\PSWorkflowCompilation\Workflow_f8de811dc1ff4612b48fe9cc0c69d546\Project\rl5vmykt.eca.xaml : error XC1014: Assembly 'Microsoft.PowerShell.Commands.Utility, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' can not be resolved. Please add a reference to this assembly in the project that is being built.
7 Warning(s)
3 Error(s)

Time Elapsed 00:00:03.05