• 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


  • 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
    

  • 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 
    

  • 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.


  • 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!


  • 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.


  • 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!


  • Microsoft Certified Solutions Expert: Cloud Platform and Infrastructure

    I just became a Microsoft Certified Solutions Expert: Cloud Platform and Infrastructure (MCSE) !
    I haven’t taken any new exams in over a year – I guess I already had enough of the requirements !

    Nice?