Author Archive | jbmurphy

Removing machines from Azure State Configuration (DSC)

I have been provisioning machines over an over trying to learn all the VM Extensions. One of the extensions that I have been playing with is the DSC extension. Every time I provision with this extension, it adds an additional record into the State Configuration, resulting in many stale machines. I wanted to clear out all the old machines. I couldn’t find a way to do it in PowerShell, so I figure out how to do it via the REST API (and PowerShell).

Here is the code to remove all machines from Azure State Configuration (DSC)

$SubscriptionId = "$($env:SubscriptionId)"
$TenantId       = "$($env:TenantId)" 
$ClientID       = "$($env:ClientID)"      
$ClientSecret   = "$($env:ClientSecret)"  
$TenantDomain   = "$($env:TenantDomain)" 
$loginURL       = "https://login.microsoftonline.com/$TenantId/oauth2/token"
$resource       = "https://management.core.windows.net/"    
$resourceGroupName = "YourResourceGroupName "
$automationAccountsName ="YourAutomationAccountsName "

# get the OAUTH token & prepare header
$body           = @{grant_type="client_credentials";resource=$resource;client_id=$ClientID;client_secret=$ClientSecret}
$oauth          = Invoke-RestMethod -Method Post -Uri $loginURL -Body $body
$headerParams = @{'Authorization'="$($oauth.token_type) $($oauth.access_token)"}

# main query to find all the nodes
$url="https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Automation/automationAccounts/$automationAccountsName/nodes?api-version=2018-01-15"
$results=Invoke-RestMethod -Uri $url -Headers $headerParams -Method Get
# Loop through all the nodes and delete them all.
foreach ($node in $($results.value | Select-Object  -ExpandProperty properties | Select nodeid)){
$url="https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Automation/automationAccounts/$automationAccountsName/nodes/$($node.nodeId)?api-version=2018-01-15"
Invoke-RestMethod -Uri $url -Headers $headerParams -Method Delete
}

Notes:

  1. I put all my SPN info into environmental varaibles (easier to switch of needed)
  2. Put in your RG name and Auutomation Account Name
  3. Warning. This will delete all nodes!

HTH

0

My WSL/BASH setup

Not sure if this a “Bootstrap” or not, but I wanted to have my WSL/Bash home directory match my windows home directory. This is the code that I use when I setup a new WSL/BASH instance.

This will find your home directory via PowerShell and put it in a variable “$WINHOME”.

Then I make make soft links to the directories in my “My Documents”.

Finally, I add the first part to my .bashrc. (lines 1-4)


WINHOME=/mnt/$(powershell.exe -noprofile -noninteractive -command '& {(gci env:USERPROFILE).Value}')
WINHOME=$(echo $WINHOME | sed 's/\\/\//g' | sed 's/\r$//' | sed 's/\://g' )
WINHOME=$(echo ${WINHOME/C/c})
export WINHOME=$WINHOME

ln -s $WINHOME/Documents
ln -s $WINHOME/Downloads
0

My SSL/Certificate Cheatsheet

Whenever a certificate needs to be renewed, I always have to scramble to remember how to update/renew. I finally put a cheat sheet together.

I decided I will do all cert related stuff form Linux. Here are some commands:

To request a new csr with a new key:

openssl req -newkey rsa:2048 -keyout yourcompany.com.key -out yourcompany.com.csr

Generating a 2048 bit RSA private key
.............................................................................................+++
.............+++
writing new private key to 'stratgovadvisors.com'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:New York
Locality Name (eg, city) []:New York
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Your Company name
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:*.yourcompany.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

To request a new csr with an existing key:

openssl req -new -key yourcompany.com.key -out yourcompany.com.csr 

To make a PFX form a Private key and a cert:

openssl pkcs12 -export -out yourcompany.com.pfx -inkey yourcompany.com.key -in yourcompany.com.crt

To extract Private key and Cert from a PFX (3 steps)

Export the private key

openssl pkcs12 -in yourcompany.com.pfx -nocerts -out yourcompany.com.pem -nodes

Export the certificate

openssl pkcs12 -in yourcompany.com.pfx -nokeys -out yourcompany.com.crt

Remove the passphrase from the private key

openssl rsa -in yourcompany.com.pem -out yourcompany.com.key 
0

My PowerShell scripts to encrypt Azure VM disks

This is my steps that I took from this very long document.

First we need to create a Key vault and then an AAD application, then you connect them. Make note of the output of $aadClientID.

$KeyVaultName="YourName-EastUS"
$ResourceGroupName="Default-EastUS"
$Location="East US"


#Create New KeyVault
New-AzureRmKeyVault -VaultName $KeyVaultName -ResourceGroupName $ResourceGroupName -Location $Location

#Create New AAD Application
$aadClientSecret = "YourLongSecret"
$azureAdApplication = New-AzureRmADApplication -DisplayName "Encryption-EastUS" -HomePage "https://IThinkAnythingCanGoHere" -IdentifierUris "https://IThinkAnythingCanGoHereURi" -Password $aadClientSecret
$servicePrincipal = New-AzureRmADServicePrincipal -ApplicationId $azureAdApplication.ApplicationId
$aadClientID = $azureAdApplication.ApplicationId
$aadClientID
Set-AzureRmKeyVaultAccessPolicy -VaultName $KeyVaultName -ServicePrincipalName $aadClientID -PermissionsToKeys all -PermissionsToSecrets all -ResourceGroupName $ResourceGroupName;
Set-AzureRmKeyVaultAccessPolicy -VaultName $KeyVaultName -EnabledForDiskEncryption

Once that is setup, you can encrypt a VM:

$KeyVaultName="YourName-EastUS"
$ResourceGroupName="Default-EastUS"
$Location="East US"
$vmName="VMNAME"

$aadClientSecret = "YourLongSecret"
$aadClientID = "YouMadeNoteOfThisAbove"
$KeyVault = Get-AzureRmKeyVault -VaultName $KeyVaultName -ResourceGroupName $ResourceGroupName;
$diskEncryptionKeyVaultUrl = $KeyVault.VaultUri;
$KeyVaultResourceId = $KeyVault.ResourceId;

Set-AzureRmVMDiskEncryptionExtension -ResourceGroupName $ResourceGroupName -VMName $vmName -AadClientID $aadClientID -AadClientSecret $aadClientSecret -DiskEncryptionKeyVaultUrl $diskEncryptionKeyVaultUrl -DiskEncryptionKeyVaultId $KeyVaultResourceId;

If you did not make note of your aadClientID, then you run:

get-AzureRmADApplication

And the ApplicationId is what you are looking for.

I forgot how I set this up, so I went back and made some notes, and now I hope this helps someone.

3

Using git and a post-recive to update production node.js apps.

I have been trying to figure out the best way to deploy and maintain node.js apps in development and production. If I have a local git repo on my machine, and I want to push it to production, what is the best way to do this? I don’t think the .git files should be there. I also don’t keep my modules in the repo, so I need a way to push updates, and make sure the newest dependencies are on the server.
I figured out that people are using a post-recieve script to update the site. This is what I ended up with. You put it in a file named post-receive in the hooks folder (on the server not on your local repo)

#!/bin/sh
GIT_WORK_TREE=/opt/node/nodapp
git --work-tree=$GIT_WORK_TREE checkout --force
cd $GIT_WORK_TREE
npm install

I may take this a step further and recycle pm2, but that is another post!

0

Using PowerShell to extract all contacts from MS CRM 2011

We are moving to Salesforce from MSCRM 2011. We need to get our data out so we can import into Salesforce. Here is the PowerShell script I am using to export contacts to csv.

$url="http://crm.sardverb.com/Company/xrmservices/2011/OrganizationData.svc/ContactSet?`$filter=StatusCode/Value eq 1"

$assembly = [Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions")
$count=0
$output = @()

while ($url){
    function GetData ($url) {
    $webclient = new-object System.Net.WebClient
    $webclient.UseDefaultCredentials = $true
    $webclient.Headers.Add("Accept", "application/json")
    $webclient.Headers.Add("Content-Type", "application/json; charset=utf-8");
    $data=$webclient.DownloadString($url)
    return $data
    }
    $data=GetData($url) | ConvertFrom-Json
    $output += $data
    $count=$count+$data.d.results.length
    write-host $count
    if ($data.d.__next){
        #$url=$null
        $url=$data.d.__next.ToString()
    }
    else {
        $url=$null
    }
}

$output.d.results | Select -ExcludeProperty ParentCustomerId,__metadata @{l="ParentCustomerID";e={$_.ParentCustomerID.Id}},* | Export-Csv -NoTypeInformation C:\Contact.csv

Hope that helps someone.

0

When using PowerShell to pull REST data from MS CRM, escape `$filter !

Note to self.

When trying to filter a REST response in PowerShell, by using the “$filter” parameter in the url (as with MS CRM 2011), you must escape the “$” with “`$”.

For example:

Does not work:
$url=”http://crmserver.company.com/Organization/xrmservices/2011/OrganizationData.svc/ContactSet$filter=StateCode/Value eq 0″

Works:
$url=”http://crmserver.company.com/Organization/xrmservices/2011/OrganizationData.svc/ContactSet`$filter=StateCode/Value eq 0″

Gets me every time, and I can’t figure out why my filters are being ignored!

2

Using jsforce and node.js to connect to Salesforce

I wanted to write a node.js app to pull data from Salesforce. I found the NPM library jsforce. I added it to my packages in my package.json:

  "dependencies": {
    "express": "*",
    "dotenv": "*",
    "jsforce": "*"
  }

I also added “dotenv” which I am using to load my client secret and all configuration data from a hidden .env file. This is not in my git repo, so I can have different values in production and development.

Here is what I have in my .env file:

CLIENTID=zWHRIM8F87FChMcfHpZKS9LhQeeLwfthDbaiL9iXNO7ZBwfUwFPFqpDzC2HruNkJfIxrOdeITtftxBg20WEIm
CLIENTSECRET=123456789987654
REDIRECTURI=localhost
[email protected]
PASSWORD=PASSWORDANDCODE
LOGINURL=https://sitename-dev-ed.my.salesforce.com

Here is the code to pull in the .env values, define the oauth2 connection and login.

var dotenv         = require('dotenv').load();
var conn = new jsforce.Connection({
  oauth2 : {
      loginUrl : process.env.LOGINURL,
      clientId : process.env.CLIENTID,
      clientSecret : process.env.CLIENTSECRET,
      redirectUri : process.env.REDIRECTURI
    }
});
var username = process.env.USERNAME;
var password = process.env.PASSWORD;
conn.login(username, password, function(err, userInfo) {
  if (err) { return console.error(err); }
  console.log(conn.accessToken);
  console.log(conn.instanceUrl);
  console.log("User ID: " + userInfo.id);
  console.log("Org ID: " + userInfo.organizationId);
});

Once connected and logged in, we can query using SOQL. This is a query to pull All Opportunities, their contacts and contact roles, and their team members and the team member roles. If that makes sense. I am using this query to show the relationships between Opportunities and their Contacts and team members using d3.js. More on that later.

    var query = "SELECT Id, Name,(SELECT Contact.Name,Contact.Email,Contact.Id,Contact.AccountId,ContactId,Role,Contact.Account.Name FROM OpportunityContactRoles),(SELECT User.Name,User.Email,User.Id,UserId,TeamMemberRole FROM OpportunityTeamMembers) FROM Opportunity"
    conn.query(query, function(err, results) {
      if (err) { return console.error(err); }
      console.log("Query: " + results.totalSize)
      console.log(JSON.stringify(results, null, 2))
    });
0