Archive | PowerShell

Moving to the new (and future) Azure PowerShell Module : Az

It looks like we need to move to the new Az module. It is not required, but future functionality will not be added to AzureRM, so I decided to make the switch. Here is how I went about it.

First, to enable backwards compatibility, you need to add this command to your profile : “Enable-AzureRmAlias” . You can edit your profile and append the line by:

notepad $profile

or you can just append it by:

Add-Content $profile "`nEnable-AzureRmAlias"

(remeber ISE has it’s own $profile so you may need to modify it too)

Once you have “Enable-AzureRmAlias” in your profile, all your old scripts should still work.

Next, I wanted to remove all the old AzureRM modules. I had several versions installed, so it took a long time! Note: this code removes any module that starts with Azure*

foreach ($module in (Get-Module -ListAvailable Azure*).Name) {
    write-host "Removing Module $module"
    Uninstall-module $module -Force
}

Now that we are feeling clean, add the new module:

Install-Module Az

For some reason it didn’t install the new Az resource graph module so I added it:

Install-Module Az.ResourceGraph

I am ready for the future. Hope that helps someone.

0

Code to query Azure Load Balancer Metrics to verify Availability (VipAvailability )

This one was fun to put together.

I wanted to write code to query the status of an Azure Load Balancer. I couldn’t find much out there. This code query’s the Azure Load Balancer’s Metrics for VipAvailability – through the REST API. If it returns 100 then are good to go. Anyting else, then there may be a issue. You can query any metric, and you can set a time range, I am just looking at the last min.

Note: This is for a Standard Load Balancer, not Basic.

Some of the Metrics Available:

VipAvailability : Average count of availability of VIP endpoints, based on probe results.
DipAvailability : Average count of availability of DIP endpoints, based on probe results.
ByteCount : Total number of bytes processed per front-end.
PacketCount : Total number of packets processed per front-end.
SynCount : Total number of SYN packets received.
SnatConnectionCount : Total number of new SNAT connections, that is, outbound connections that are masqueraded to the Public IP address front-end.

And the same metrics are often referred to by different names (this was confusing to me):

value               localizedValue                
-----               --------------                
VipAvailability     Data Path Availability        
DipAvailability     Health Probe Status           
ByteCount           Byte Count                    
PacketCount         Packet Count                  
SYNCount            SYN Count                     
SnatConnectionCount SNAT Connection Count         
AllocatedSnatPorts  Allocated SNAT Ports (Preview)
UsedSnatPorts       Used SNAT Ports (Preview) 

Here is the code (bouns: BASH/cURL too) to find the VipAvaiablity of Azure Load Balancers:

$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 = "eastUS-01"
$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)"}

$start=((Get-Date).AddMinutes(-1)).ToUniversalTime().ToString("yyy-MM-ddTHH:mm:00Z")
$end=(Get-Date).ToUniversalTime().ToString("yyy-MM-ddTHH:mm:00Z")
$filter = "(name.value eq 'VipAvailability') and aggregationType eq 'Average' and startTime eq $start and endTime eq $end and timeGrain eq duration'PT1M'"
$url = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Network/loadBalancers/jemurphyLB01/providers/microsoft.insights/metrics?`$filter=${filter}&api-version=2016-09-01"
$results=Invoke-RestMethod -Uri $url -Headers $headerParams -Method Get
$results.value | select -ExpandProperty data | select timestamp,average
SUBSCRIPTIONID=""
RESOURCEGROUPNAME=""
CLIENTID=""
CLIENTSECRET=""
TENANTID=""
RESOURCEGROUPNAME=""
LBNAME=""

LOGINURL="https://login.microsoftonline.com/$TENANTID/oauth2/token"
RESOURCE="https://management.core.windows.net/" 

TOKEN=$(curl --silent --request POST $LOGINURL --data-urlencode "resource=https://management.core.windows.net" --data-urlencode "client_id=$CLIENTID" --data-urlencode "grant_type=client_credentials" --data-urlencode "client_secret=$CLIENTSECRET" | jq -r '.access_token')

STARTTIME=$(date -u +'%Y-%m-%dT%H:%M:00' --date='-1 min')
ENDTIME=$(date -u +'%Y-%m-%dT%H:%M:00')

FILTER="(name.value eq 'VipAvailability') and aggregationType eq 'Average' and startTime eq $STARTTIME and endTime eq $ENDTIME and timeGrain eq duration'PT1M'"
URL="https://management.azure.com/subscriptions/$SUBSCRIPTIONID/resourceGroups/$RESOURCEGROUPNAME/providers/Microsoft.Network/loadBalancers/$LBNAME/providers/microsoft.insights/metrics"

RESULTS=$(curl -s -G --header "authorization: Bearer $TOKEN" --data-urlencode "\$filter=$FILTER" --data-urlencode "api-version=2016-09-01" $URL | jq .value[].data[].average)

echo "$RESULTS"

I think the hardest part was trying to get the date and time in the right format. Why is that so hard?

This HAS to be helpful to some one!

0

Using Azure Traffic Manager with IP White-listed resources

The question was, how can you use Azure Traffic Manager if the destinations are restricted with IP white lists?
This is the only way I could find:

  1. There is a blob that contains the source IPs of the probes. Here is the file, And here is the reference
  2. This list would need to be queried often because I couldn’t find any indication of when it would be updated
  3. I wrote PowerShell to parse the results and put it into an NSG.

$RGName= "Your RG Name"
$NSGName = "Your NSG Name"
$NSGRuleName = "Your Rule Name"
$Priority = 120
$DestinationPortRange = 443
$url="https://azuretrafficmanagerdata.blob.core.windows.net/probes/azure/probe-ip-ranges.json"
$results=Invoke-RestMethod -Uri $url
$allAddresses=@()
foreach ($address in $results.ipv4_prefixes){
$allAddresses += $address.ip_prefix
}
# for some reason, get-AzureRmNetworkSecurityRuleConfig errors out if there is no matchin name
# could use a try - catch
if  ((Get-AzureRmNetworkSecurityGroup -ResourceGroupName $RGName -Name $NSGName | get-AzureRmNetworkSecurityRuleConfig -Name $NSGRuleName -ErrorAction SilentlyContinue) -eq $null){
# Creating RUle
Get-AzureRmNetworkSecurityGroup -ResourceGroupName $RGName -Name $NSGName | `
Add-AzureRmNetworkSecurityRuleConfig -Name $NSGRuleName -Description "Allow Probe from ATM" -Access Allow -Protocol Tcp -Direction Inbound -Priority $Priority -SourceAddressPrefix $allAddresses -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange $DestinationPortRange | Set-AzureRmNetworkSecurityGroup
}
else {
# Updating Rule
Get-AzureRmNetworkSecurityGroup -ResourceGroupName $RGName -Name $NSGName | `
Set-AzureRmNetworkSecurityRuleConfig -Name $NSGRuleName -Description "Allow Probe from ATM" -Access Allow -Protocol Tcp -Direction Inbound -Priority $Priority -SourceAddressPrefix $allAddresses -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange $DestinationPortRange | Set-AzureRmNetworkSecurityGroup
}

Hope that helps.

0

PowerShell to move a VM to a new Log Analytics WorkSpace

This code uninstalls the Microsoft Monitoring agent and re-installs it to a new WorkSpace.


# change your VM Name and it's resource group
$vm = get-azurermvm -VMName YourVMName -ResourceGroupName VMResourceGroup
Remove-AzureRmVMExtension -ResourceGroupName $vm.ResourceGroupName -VMName $vm.Name -Name MicrosoftMonitoringAgent -Force
# put in your new workspaceId & workspaceKey
$workspaceId = "NewWorksSpaceID"
$workspaceKey = "SupaSecretKey"

$PublicSettings = @{"workspaceId" = $workspaceId;"stopOnMultipleConnections" = $false}
$ProtectedSettings = @{"workspaceKey" = $workspaceKey}

Set-AzureRmVMExtension -ExtensionName "MicrosoftMonitoringAgent" -ResourceGroupName $vm.resourcegroupname -VMName $vm.name `
-Publisher "Microsoft.EnterpriseCloud.Monitoring" `
-ExtensionType "MicrosoftMonitoringAgent" `
-TypeHandlerVersion 1.0 `
-Settings $PublicSettings `
-ProtectedSettings $ProtectedSettings `
-Location $vm.Location

Nothing special, just thought I would put it here. Mayby it will help someone?

0

Use the REST API to create a new Project in Azure DevOps

As the title says, I wanted to create a new project in VSTS / Azure DevOps, whatever you want to call it. Here is the code to do that. You need a Personal Access Token to authenticate with.

$User="yourusername@yourdomain.com"
$PAT="YourPAT"
$Organization="YourOrg"
$base64authinfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $User, $PAT)))
$url="https://dev.azure.com/$Organization/_apis/projects?api-version=5.1-preview.4"
$body = @"
{
  "name": "FabrikamTravel",
  "description": "Frabrikam travel app for Windows Phone",
  "capabilities": {
    "versioncontrol": {
      "sourceControlType": "Git"
    },
    "processTemplate": {
      "templateTypeId": "6b724908-ef14-45cf-84f8-768b5384da45"
    }
  }
}
"@
Invoke-RestMethod -Method POST -ContentType application/json -Uri $url -Headers @{Authorization=("Basic {0}" -f $base64authinfo)} -Body $Body

Hope that helps someone?

0

Using PowerShell to query Azure Log Analytics via the REST API

I wanted to pull some data out of Azure Log Analytics using PowerShell and the REST API. Here is the code to Pull all errors in the Application event logs on VMs that are pushing their logs into Log Analytics via MicrosoftMonitoringAgent.

Hopefully this may help someone:

$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://api.loganalytics.io"         

$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)"}

$Workspacename="Your WS Name"
$WorkspaceId="Your WS ID"

$url="https://api.loganalytics.io/v1/workspaces/$WorkspaceId/query"
$body = @{query = 'Event | where EventLog == "Application" | order by TimeGenerated asc | project Computer,EventLog,Source,EventLevelName,EventID,RenderedDescription,TimeGenerated'} | ConvertTo-Json
$webresults=Invoke-RestMethod -UseBasicParsing -Headers $headerParams -Uri $url -Method Post -Body $body -ContentType "application/json"

Notes:

  1. I keep my subscription information in Env Varaibles. It is easier for me to swtich to a different Tenant
  2. ¬†This returns the results in tables. To move the tables into an object look at this person’s code at line 60¬† https://blog.tyang.org/2017/11/14/searching-oms-using-the-new-search-language-kusto-rest-api-in-powershell/
  3. My interpretation of code in #2
$resultsTable=$webresults.Content | ConvertFrom-Json
$count = 0
foreach ($table in $resultsTable.Tables) {
$count += $table.Rows.Count
}
$results = New-Object object[] $count
$i = 0;
foreach ($table in $resultsTable.Tables) {
    foreach ($row in $table.Rows) {
        # Create a dictionary of properties
        $properties = @{}
        for ($columnNum=0; $columnNum -lt $table.Columns.Count; $columnNum++) {
            $properties[$table.Columns[$columnNum].name] = $row[$columnNum]
        }      
        $results[$i] = (New-Object PSObject -Property $properties)
        $null = $i++
    }
}
$results



0

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

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

Connecting to the Salesforce REST api using PowerShell

As I said in my previous post, we are starting to use Salesforce, and I like REST APIs, so I wanted to see how to connect to Salesforce with cuRL and PowerShell.

cURL was pretty easy, PowerShell was not so much. The biggest issue was that when I queried the standard “https://login.salesforce.com/services/oauth2/token” url, I would get one response back, but if I tried again, it wouldn’t work. I had to install fiddler to figure out what was going on. I finally found the error and this solution: use your instance ID in the URL. That took me half a day to figure out. Add-on a typo of not having https in the URL, and I was not having fun. Once I figured out that you need to use your instance url and https I hit this error:

salesforce stronger security is required

So I had to figure out how to force Invoke-WebRequest or Invoke-RestMethod to use TLS 1.2. Here is the code that I finnanly figred out that gets an access token and queries accounts.


[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$tokenurl = "https://InstanceName-dev-ed.my.salesforce.com/services/oauth2/token"
$postParams = [ordered]@{
grant_type="password";
client_id="ReallyLongClientIDReallyLongClientIDReallyLongClientIDReallyLongClientIDReallyLongCli";
client_secret="1234567890123456789";
username="bob@aol.com";
password="PasswordAndTokenNoSpaces";
}

$access_token=(Invoke-RestMethod -Uri $tokenurl -Method POST -Body $postParams).access_token

$url = "https://InstanceName-dev-ed.my.salesforce.com/services/data/v37.0/sobjects/Account"
Invoke-RestMethod -Uri $url -Headers @{Authorization = "Bearer " + $access_token}


you don’t need the [ordered] part of the hash table, i was just using it to troubleshoot.

4

Hidden or UnDocumented Network Security Group (NSG) default rule in Azure (DNS)

I have been working to get a Citrix Netscaler up and running in Azure. It has not been easy, as all the documentation is for ASM.

Our network configuration has IPSec tunnels going from OnPrem to Azure, and I have created two SubNets in Azure – a DMZ and a LAN. The DMZ has the following Outbound NSG rules (ACLs) for the NetScaler to talk to a LAN SubNet.

Get-AzureRmNetworkSecurityGroup -ResourceGroupName ResourceGroupName | Select SecurityRules -ExpandProperty SecurityRules | where {$_.Direction -eq "Outbound"} | Select Priority,Name,Protocol,SourceAddressPrefix,SourcePortRange,DestinationAddressPrefix,DestinationPortRange,Access | Sort-Object Priority|ft -AutoSize

DMZ Netscaler = 192.10.8.100
LAN DC = 192.10.9.10

Priority Name                           Protocol SourceAddressPrefix SourcePortRange DestinationAddressPrefix DestinationPortRange Access
-------- ----                           -------- ------------------- --------------- ------------------------ -------------------- ------
     101 LDAP_From_NSIP                 TCP      192.10.8.100        *               192.10.9.10              389                  Allow
     102 DNSUDP_From_NSIP               Udp      192.10.8.100        *               192.10.9.10              53                   Allow
     103 DNSTCP_From_NSIP               TCP      192.10.8.100        *               192.10.9.10              53                   Allow
     104 RADIUS_From_NSIP               Udp      192.10.8.100        *               192.10.9.10              1812                 Allow
    4095 Subnet_To_Internet             *        *                   *               Internet                 *                    Allow
    4096 Deny_All_Outbound              *        *                   *               *                        *                    Deny

As you can see, I add a DenyAll at the end even though there is one in the DefaultSecurityRules. I just like to see it there. I find it comforting.

I found that from then Netscaler, I could do a DNS lookup against my OnPrem DC. How can that be?
Rule 101-104 are only for the Azure LAN DC. Then I DenyAll with 4096.
How can the Netscaler look up via the OnPrem DC?
I am DenyingAll!
I was pulling my hair out.

I realized that I had never changed my DNS server settings for my Virtual Network in Azure (I needed it to join the domain for the local DC when I build it!). I forgot to switch it the local Azure LAN DC.

Therefore, even though there is a DenyAll in my NSG rules, there has to be a Hidden or UnDocumented rule that allows queries to the DNS servers listed in the Virtual Network settings.

As soon as I changed the DNS server settings to the local Azure LAN DC, I could no longer query the OnPrem DC.

I understand why it is there. If you put in a DenyAll (like I did), Windows Servers will panic. They do not like it if they can’t access a DNS server.

I think Azure needs to move the DNS server settings down to the SubNet level, since all VMs are DHCP (Reservations). If they do this, a DMZ and LAN can use different DNS server settings, or none at all.

Just something I ran across today.

0

Powered by WordPress. Designed by WooThemes