diff --git a/services/cloud-services/CreateAffinityGroupIfNotExists.ps1 b/services/cloud-services/CreateAffinityGroupIfNotExists.ps1 new file mode 100644 index 0000000..1ad0fc6 --- /dev/null +++ b/services/cloud-services/CreateAffinityGroupIfNotExists.ps1 @@ -0,0 +1,45 @@ +<# +.SYNOPSIS + Adds a new affinity group if it does not exist. +.DESCRIPTION + Looks up the current subscription's (as set by Set-AzureSubscription cmdlet) affinity groups and creates a new + affinity group if it does not exist. +.EXAMPLE + New-AzureAffinityGroupIfNotExists -AffinityGroupNme newAffinityGroup -Locstion "West US" +.INPUTS + None +.OUTPUTS + None +#> +function New-AzureAffinityGroupIfNotExists +{ + Param + ( + # Name of the affinity group + [Parameter(Mandatory = $true)] + [string] + $AffinityGroupName, + + # Location where the affinity group will be pointing to + [Parameter(Mandatory = $true)] + [string] + $Location) + + $affinityGroup = Get-AzureAffinityGroup -Name $AffinityGroupName -ErrorAction SilentlyContinue + if ($affinityGroup -eq $null) + { + New-AzureAffinityGroup -Name $AffinityGroupName -Location $Location -Label $AffinityGroupName -ErrorVariable lastError -ErrorAction SilentlyContinue | Out-Null + if (!($?)) + { + throw "Cannot create the affinity group $AffinityGroupName on $Location" + } + Write-Verbose "Created affinity group $AffinityGroupName" + } + else + { + if ($affinityGroup.Location -ne $Location) + { + Write-Warning "Affinity group with name $AffinityGroupName already exists but in location $affinityGroup.Location, not in $Location" + } + } +} diff --git a/services/cloud-services/place-holder.txt b/services/cloud-services/place-holder.txt deleted file mode 100644 index e69de29..0000000 diff --git a/services/networks/CreateVNetSiteIfNotExists.ps1 b/services/networks/CreateVNetSiteIfNotExists.ps1 new file mode 100644 index 0000000..aa3400e --- /dev/null +++ b/services/networks/CreateVNetSiteIfNotExists.ps1 @@ -0,0 +1,62 @@ +<# +.Synopsis + Creates a Virtual Network Site if it does not exist and sets the subnet details. +.DESCRIPTION + Creates the VNet site if it does not exist. It first downloads the neetwork configuration for the subscription. + If there is no network configuration, it creates an empty one first using the Add-AzureVnetConfigurationFile helper + function, then updates the network file with the provided Vnet settings also by adding the subnet. +.EXAMPLE + New-VNetSiteIfNotExists -VNetSiteName testVnet -SubnetName mongoSubnet -AffinityGroupName mongoAffinity +#> +function New-VNetSiteIfNotExists +{ + [CmdletBinding()] + Param + ( + # Name of the Vnet site + [Parameter(Mandatory = $true)] + [string] + $VNetSiteName, + + # Name of the subnet + [Parameter(Mandatory = $true)] + [string] + $SubnetName, + + # THe affinity group the vnet will be associated with + [Parameter(Mandatory = $true)] + [string] + $AffinityGroupName, + + # Address prefix for the Vnet. For the sake of examples in this scripts, + # the smallest address space possible for Azure is default + [String]$VNetAddressPrefix = "10.0.0.0/8", + + # The name of the subnet to be added to the Vnet + [String] $DefaultSubnetName = "Subnet-1", + + # Addres space for the Subnet + [String] $SubnetAddressPrefix = "10.0.0.0/29") + + # Check the VNet site, and add it to the configuration if it does not exist. + $vNet = Get-AzureVNetSite -VNetName $VNetSiteName -ErrorAction SilentlyContinue + if ($vNet -eq $null) + { + $vNetFilePath = "$env:temp\$AffinityGroupName" + "vnet.xml" + Get-AzureVNetConfig -ExportToFile $vNetFilePath | Out-Null + if (!(Test-Path $vNetFilePath)) + { + Add-AzureVnetConfigurationFile -Path $vNetFilePath + } + + Set-VNetFileValues -FilePath $vNetFilePath -VNet $vNetSiteName -DefaultSubnetName $SubnetName -AffinityGroup $AffinityGroupName -VNetAddressPrefix $VNetAddressPrefix -SubnetAddressPrefix $SubnetAddressPrefix + Set-AzureVNetConfig -ConfigurationPath $vNetFilePath -ErrorAction SilentlyContinue -ErrorVariable errorVariable | Out-Null + if (!($?)) + { + throw "Cannot set the vnet configuration for the subscription, please see the file $vNetFilePath. Error detail is: $errorVariable" + } + Write-Verbose "Modified and saved the VNET Configuration for the subscription" + + Remove-Item $vNetFilePath + } +} \ No newline at end of file diff --git a/services/networks/place-holder.txt b/services/networks/place-holder.txt deleted file mode 100644 index e69de29..0000000 diff --git a/services/sql-databases/CreateSQLServerDatabaseFirewall.ps1 b/services/sql-databases/CreateSQLServerDatabaseFirewall.ps1 new file mode 100644 index 0000000..a7c7064 --- /dev/null +++ b/services/sql-databases/CreateSQLServerDatabaseFirewall.ps1 @@ -0,0 +1,74 @@ + +<# +.SYNOPSIS + Creates a SQL server and database with firewall rule +.DESCRIPTION + Creates a SQL Server with firewall rule in a sub region. Then create a database on the newly created server. + +#> + + +# Setting up the subscription info and the certificate +# to be used when connecting to the subscription +# +# This needs to be done once per subscription on each +# new client machine +# Enter values for thumbprint and subscription ID +$thumbprint = "Enter thumbprint Here" +$myCert = Get-Item cert:\\CurrentUser\My\$thumbprint +$subID = "Enter SUBid Here" +Set-AzureSubscription -SubscriptionName "Example" -SubscriptionId $subID -Certificate $myCert + +#Example +#$thumbprint = "0000000000000000000000000000000000000000" +#$myCert = Get-Item Cert:\CurrentUser\My\$thumbprint +#$subId = "00000000-0000-0000-0000-000000000000" + +# Select the active subscription to be used +# for the rest of the script +# +Select-AzureSubscription -SubscriptionName "Example" +Get-AzureSubscription + +# See all servers in the subscription +Get-AzureSqlDatabaseServer + +# Create a new server in West US region, and check the servers again +$serverLogin = "mylogin" +$serverPassword = "Sql@zure" +$server = New-AzureSqlDatabaseServer -AdministratorLogin $serverLogin -AdministratorLoginPassword $serverPassword -Location "West US" +Get-AzureSqlDatabaseServer + +# Get just newly created server +$server | Get-AzureSqlDatabaseServer + +# Get all firewall rules in all servers in subscription +Get-AzureSqlDatabaseServer | Get-AzureSqlDatabaseServerFirewallRule + + +# Add a new firewall rule : This rule opens all IPs to the server and is just an example - not recommended +$server | New-AzureSqlDatabaseServerFirewallRule -RuleName AllOpen -StartIPAddress 0.0.0.0 -EndIPAddress 255.255.255.255 + +# Check the firewall rules again +Get-AzureSqlDatabaseServer | Get-AzureSqlDatabaseServerFirewallRule + +# To create a database on the server +# Connect to the server using Sql Authentication +# +$servercredential = new-object System.Management.Automation.PSCredential("mylogin", ("Sql@zure" | ConvertTo-SecureString -asPlainText -Force)) +$ctx = $server | New-AzureSqlDatabaseServerContext -Credential $serverCredential + +# List databases +# +Get-AzureSqlDatabase $ctx + +# Create a new database +# +$db = New-AzureSqlDatabase $ctx -DatabaseName Demo +Get-AzureSqlDatabase $ctx + +# Instead of creating a SQL Authentication context it is possible to also directly pipe in the server object. +#This will use your certificate authentication to create the SQL SB +# +$server | New-AzureSqlDatabase DatabaseName example + diff --git a/services/sql-databases/ManagePremiumSQLDatabases.ps1 b/services/sql-databases/ManagePremiumSQLDatabases.ps1 new file mode 100644 index 0000000..c0eb6f0 --- /dev/null +++ b/services/sql-databases/ManagePremiumSQLDatabases.ps1 @@ -0,0 +1,84 @@ + +<# +.SYNOPSIS + Manage Premium SQL Databases +.DESCRIPTION + Script will walk you through checking premium quota and managing premium database reservations. + +#> + + +# Setting up the subscription info and the certificate +# to be used when connecting to the subscription +# +# This needs to be done once per subscription on each +# new client machine +# Enter values for thumbprint and subscription ID +$thumbprint = "Enter thumbprint Here" +$myCert = Get-Item cert:\\CurrentUser\My\$thumbprint +$subID = "Enter SUBid Here" +Set-AzureSubscription -SubscriptionName "Example" -SubscriptionId $subID -Certificate $myCert + +#Example +#$thumbprint = "0000000000000000000000000000000000000000" +#$myCert = Get-Item Cert:\CurrentUser\My\$thumbprint +#$subId = "00000000-0000-0000-0000-000000000000" + + +# Select the active subscription to be used +# for the rest of the script +# +Select-AzureSubscription -SubscriptionName "Example" +Get-AzureSubscription + +# See all servers in the subscription +Get-AzureSqlDatabaseServer + +# Assign server +$server = Get-AzureSqlDatabaseServer "DemoServer" + + +######Check Premium database quota.########################### + +# This command will list if you have been assigned premium quota. Premium database quota must be requested for your server via the Windows Azure Management Portal + +Get-AzureSqlDatabaseServerQuota $ctx + +$ctx | Get-AzureSqlDatabaseServerQuota + + + +########Change reservation size of a Premium database.########################### + + +$servercredential = new-object System.Management.Automation.PSCredential("mylogin", ("Sql@zure" | ConvertTo-SecureString -asPlainText -Force)) +$ctx = $server | New-AzureSqlDatabaseServerContext -Credential $serverCredential + +# Get an enabled service objective +$objective = Get-AzureSqlDatabaseServiceObjective -Context $ctx -ServiceObjectiveName "Reserved P2" +$objective + + +# Assign a diffent service objective to a database NOTE: This may take a long time to complete +Set-AzureSqlDatabase -ConnectionContext $ctx -DatabaseName "testdb" -ServiceObjective $objective + + +$ctx | Get-AzureSqlDatabase -DatabaseName "testdb" + + +########Downgrade database from Permium to Shared.########################### + + +$servercredential = new-object System.Management.Automation.PSCredential("mylogin", ("Sql@zure" | ConvertTo-SecureString -asPlainText -Force)) +$ctx = $server | New-AzureSqlDatabaseServerContext -Credential $serverCredential + +# Get an enabled service objective +$objective = Get-AzureSqlDatabaseServiceObjective -Context $ctx -ServiceObjectiveName "Shared" +$objective + + +# Assign a diffent service objective to a database NOTE: This may take a long time to complete +Set-AzureSqlDatabase -ConnectionContext $ctx -DatabaseName "testdb" -ServiceObjective $objective + + +$ctx | Get-AzureSqlDatabase -DatabaseName "testdb" \ No newline at end of file diff --git a/services/sql-databases/ManageSQLDatabaseFirewall.ps1 b/services/sql-databases/ManageSQLDatabaseFirewall.ps1 new file mode 100644 index 0000000..11f3155 --- /dev/null +++ b/services/sql-databases/ManageSQLDatabaseFirewall.ps1 @@ -0,0 +1,118 @@ + +<# +.SYNOPSIS + Manage SQL Server database and firewall rules +.DESCRIPTION + Script will walk you through changing size and type of a database along with setting and removing firewall rules + +#> + + +# Setting up the subscription info and the certificate +# to be used when connecting to the subscription +# +# This needs to be done once per subscription on each +# new client machine +# Enter values for thumbprint and subscription ID +$thumbprint = "Enter thumbprint Here" +$myCert = Get-Item cert:\\CurrentUser\My\$thumbprint +$subID = "Enter SUBid Here" +Set-AzureSubscription -SubscriptionName "Example" -SubscriptionId $subID -Certificate $myCert + +#Example +#$thumbprint = "0000000000000000000000000000000000000000" +#$myCert = Get-Item Cert:\CurrentUser\My\$thumbprint +#$subId = "00000000-0000-0000-0000-000000000000" + + +# Select the active subscription to be used +# for the rest of the script +# +Select-AzureSubscription -SubscriptionName "Example" +Get-AzureSubscription + +# See all servers in the subscription +Get-AzureSqlDatabaseServer + +# Assign server +$server = Get-AzureSqlDatabaseServer "DemoServer" + + +###########Manage Firewall Rules on a server################# + + +# Get all firewall rules in all servers in subscription +Get-AzureSqlDatabaseServer | Get-AzureSqlDatabaseServerFirewallRule + +# Add a new firewall rule : This rule opens all IPs to the server and is just an example - not recommended +$server | New-AzureSqlDatabaseServerFirewallRule -RuleName AllOpen -StartIPAddress 0.0.0.0 -EndIPAddress 255.255.255.255 + + +# Get all firewall rules in all servers in subscription +Get-AzureSqlDatabaseServer | Get-AzureSqlDatabaseServerFirewallRule + +# Add a new firewall rule : This gets all the fireWall rules in the server named jt6ocnuuln and adds them to the new database server +$fwRules = Get-AzureSqlDatabaseServer -ServerName jt6ocnuuln | Get-AzureSqlDatabaseServerFirewallRule +foreach ($fwRule in $fwRules) + { $server | New-AzureSqlDatabaseServerFirewallRule -RuleName $fwRule.RuleName -StartIpAddress $fwRule.StartIpAddress -EndIpAddress $fwRule.EndIpAddress } + + +# Create a new rule that allows all Azure Service to access the server +New-AzureSqlDatabaseServerFirewallRule -ServerName "fk1ucgo5xr" -RuleName "myRule" -AllowAllAzureServices + +# Create a new rule that allows all Azure Service to access the server by piping in server object +$Server | New-AzureSqlDatabaseServerFirewallRule -AllowAllAzureServices + + +# Check the firewall rules again +Get-AzureSqlDatabaseServer | Get-AzureSqlDatabaseServerFirewallRule + +# Remove all 'FirewallRules' rule from all servers in subscription +Get-AzureSqlDatabaseServer | Get-AzureSqlDatabaseServerFirewallRule -RuleName FirewallRules | Remove-AzureSqlDatabaseServerFirewallRule -WhatIf +Get-AzureSqlDatabaseServer | Get-AzureSqlDatabaseServerFirewallRule + + +###########Manage SQL Server and Databases################# + + +# Connect to the server using Sql Authentication +# +$servercredential = new-object System.Management.Automation.PSCredential("mylogin", ("Sql@zure" | ConvertTo-SecureString -asPlainText -Force)) +$ctx = $server | New-AzureSqlDatabaseServerContext -Credential $serverCredential + +# List databases +# +Get-AzureSqlDatabase $ctx + +# Create a new database +# +$db = New-AzureSqlDatabase $ctx -DatabaseName Demo +Get-AzureSqlDatabase $ctx + +# Change database maximum size +Set-AzureSqlDatabase $ctx $db -MaxSizeGB 10 +Get-AzureSqlDatabase $ctx + +# Remove the database +$db | Remove-AzureSqlDatabaseServer + +# Remove the server +# +$server | Remove-AzureSqlDatabaseServer + +# Aleternatively to creating a SQL authentication contect you can also create a database with certifcate authentication +# Create context using certifcate authentication with Subscription information +$servercertctx = New-AzureSqlDatabaseServerContext -ServerName "exampleserver" -UseSubscription +Get-AzureSqlDatabase $servercertctx + +# Create a new database using cert auth - $server created above +# +$server | New-AzureSqlDatabase -DatabaseName "example" +$server | Remove-AzureSqlDatabase -DatabaseName "example" +$server | Get-AzureSqlDatabase -DatabaseName "example" + +# Create a new database using cert auth from ctx created with certificate authentication +# +$servercertctx | New-AzureSqlDatabase -DatabaseName "example" +$servercertctx | Remove-AzureSqlDatabase -DatabaseName "example" +$servercertctx | Get-AzureSqlDatabase -DatabaseName "example" diff --git a/services/sql-databases/New-AzureSql.ps1 b/services/sql-databases/New-AzureSql.ps1 new file mode 100644 index 0000000..7adbb9f --- /dev/null +++ b/services/sql-databases/New-AzureSql.ps1 @@ -0,0 +1,46 @@ +<# +.SYNOPSIS + creates a sql db and set server firewall rule based on the parameters location, + name, user id, password +.DESCRIPTION + This function creates a database server, sets up server firewall rules and then + creates a Database. It uses New-AzureSqlDatabaseServer cmdlet to create the server, + New-AzureSqlDatabaseServerFirewallRule to create the firewall rule, + New-AzureSqlDatabase cmdlet to create the database. + + ` +.EXAMPLE + $db = CreateDatabase -Location "West US" -AppDatabaseName "AppDatabaseName" + -UserName "UserName" -Password "Password" -RuleName "RuleName" + -FirewallRuleName "FirewallRuleName" -StartIPAddress "0.0.0.0" -EndIPAddress "0.0.0.0" +#> + + +function CreateDatabase($Location,$AppDatabaseName, $Credential, $ClientIP) +{ + # Create Database Server + Write-Verbose "Creating SQL Azure Database Server." + $databaseServer = New-AzureSqlDatabaseServer -AdministratorLogin $Credential.UserName ` + -AdministratorLoginPassword $Credential.GetNetworkCredential().Password -Location $Location + Write-Verbose ("SQL Azure Database Server '" + $databaseServer.ServerName + "' created.") + + # Apply Firewall Rules + $clientFirewallRuleName = "ClientIPAddress_" + [DateTime]::UtcNow + Write-Verbose "Creating client firewall rule '$clientFirewallRuleName'." + New-AzureSqlDatabaseServerFirewallRule -ServerName $databaseServer.ServerName ` + -RuleName $clientFirewallRuleName -StartIpAddress $ClientIP -EndIpAddress $ClientIP | Out-Null + + + $azureFirewallRuleName = "AzureServices" + Write-Verbose "Creating Azure Services firewall rule '$azureFirewallRuleName'." + New-AzureSqlDatabaseServerFirewallRule -ServerName $databaseServer.ServerName ` + -RuleName $azureFirewallRuleName -StartIpAddress "0.0.0.0" -EndIpAddress "0.0.0.0" + + # Create Database + $serverName = $databaseServer.ServerName + $context = New-AzureSqlDatabaseServerContext -ServerName $serverName -Credential $Credential + Write-Verbose "Creating database '$AppDatabaseName' in database server $serverName." + New-AzureSqlDatabase -DatabaseName $AppDatabaseName -Context $context + + return $serverName; +} diff --git a/services/sql-databases/UpgradetoPremiumSQLDatabase.ps1 b/services/sql-databases/UpgradetoPremiumSQLDatabase.ps1 new file mode 100644 index 0000000..a24c121 --- /dev/null +++ b/services/sql-databases/UpgradetoPremiumSQLDatabase.ps1 @@ -0,0 +1,65 @@ + +<# +.SYNOPSIS + Upgrade to a Premium SQL Databases +.DESCRIPTION + Script will walk you through checking premium quota assigned to your subscription. If you have premium quota allocated you can then upgrade a database to premium. + +#> + + +# Setting up the subscription info and the certificate +# to be used when connecting to the subscription +# +# This needs to be done once per subscription on each +# new client machine +# Enter values for thumbprint and subscription ID +$thumbprint = "Enter thumbprint Here" +$myCert = Get-Item cert:\\CurrentUser\My\$thumbprint +$subID = "Enter SUBid Here" +Set-AzureSubscription -SubscriptionName "Example" -SubscriptionId $subID -Certificate $myCert + +#Example +#$thumbprint = "0000000000000000000000000000000000000000" +#$myCert = Get-Item Cert:\CurrentUser\My\$thumbprint +#$subId = "00000000-0000-0000-0000-000000000000" + + +# Select the active subscription to be used +# for the rest of the script +# +Select-AzureSubscription -SubscriptionName "Example" +Get-AzureSubscription + +# See all servers in the subscription +Get-AzureSqlDatabaseServer + +# Assign server +$server = Get-AzureSqlDatabaseServer "DemoServer" + + +######Check if your server has been granted Premium database quota.########################### + +# This command will list if you have been assigned premium quota. Premium database quota must be requested for your server via the Windows Azure Management Portal + +Get-AzureSqlDatabaseServerQuota $ctx + +$ctx | Get-AzureSqlDatabaseServerQuota + +########Upgrade a database to Premium.########################### + + +$servercredential = new-object System.Management.Automation.PSCredential("mylogin", ("Sql@zure" | ConvertTo-SecureString -asPlainText -Force)) +$ctx = $server | New-AzureSqlDatabaseServerContext -Credential $serverCredential + +# Get an enabled service objective +$objective = Get-AzureSqlDatabaseServiceObjective -Context $ctx -ServiceObjectiveName "Reserved P1" +$objective + + +# Assign a service objective to a database NOTE: This may take a long time to complete +Set-AzureSqlDatabase -ConnectionContext $ctx -DatabaseName "testdb" -ServiceObjective $objective + + +$ctx | Get-AzureSqlDatabase -DatabaseName "testdb" + diff --git a/services/sql-databases/_CreateSQLServerDatabaseFirewall.md b/services/sql-databases/_CreateSQLServerDatabaseFirewall.md new file mode 100644 index 0000000..786f58b --- /dev/null +++ b/services/sql-databases/_CreateSQLServerDatabaseFirewall.md @@ -0,0 +1,12 @@ +# CreateSQLServerDatabaseFirewall # +## Description ## +Creates a SQL Server with a firewall rule in a sub region. Once server is created then create a database on the server. + +## Scenario ## +You want to create a SQL database. + +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + + diff --git a/services/sql-databases/_ManagePremiumSQLDatabases.md b/services/sql-databases/_ManagePremiumSQLDatabases.md new file mode 100644 index 0000000..5ea81b5 --- /dev/null +++ b/services/sql-databases/_ManagePremiumSQLDatabases.md @@ -0,0 +1,14 @@ +# CreateSQLServerDatabaseFirewall # +## Description ## +Script will walk you through checking if your database has been granted Permium database quota. Followed by how to change/downgrade reservations on a database. + +**Note:** Premium database quota must be requested for your server via the Windows Azure Management Portal + +## Scenario ## +You have a SQL Server with premium database quota and would like to change/downgrade reservation levels. + +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + + diff --git a/services/sql-databases/_ManageSQLDatabaseFirewall.md b/services/sql-databases/_ManageSQLDatabaseFirewall.md new file mode 100644 index 0000000..4d0dd3d --- /dev/null +++ b/services/sql-databases/_ManageSQLDatabaseFirewall.md @@ -0,0 +1,12 @@ +# CreateSQLServerDatabaseFirewall # +## Description ## +Script will walk you through changing size and type of a database along with setting and removing firewall rules + +## Scenario ## +You have a SQL Server database and would like to change database size and manage firewall rules on the server. + +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + + diff --git a/services/sql-databases/_UpgradetoPremiumSQLDatabases.md b/services/sql-databases/_UpgradetoPremiumSQLDatabases.md new file mode 100644 index 0000000..e767687 --- /dev/null +++ b/services/sql-databases/_UpgradetoPremiumSQLDatabases.md @@ -0,0 +1,14 @@ +# CreateSQLServerDatabaseFirewall # +## Description ## +Script will walk you through checking if your database has been granted Permium database quota. Followed by how to upgrade reservations on a database to premium. + +**Note:** Premium database quota must be requested for your server via the Windows Azure Management Portal + +## Scenario ## +You have a SQL Server with premium database quota and would like to upgrade ryour database to premium reservation level. + +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + + diff --git a/services/sql-databases/place-holder.txt b/services/sql-databases/place-holder.txt deleted file mode 100644 index e69de29..0000000 diff --git a/services/storage/new-cloud-service-storage-accounts.ps1 b/services/storage/new-cloud-service-storage-accounts.ps1 new file mode 100644 index 0000000..263acab --- /dev/null +++ b/services/storage/new-cloud-service-storage-accounts.ps1 @@ -0,0 +1,223 @@ +<# +.SYNOPSIS + Creates 2 storage accounts for a cloud service +.DESCRIPTION + Creates 2 storage accounts, 1 for data, 1 for diagnostics, with a name that matches a given cloud service. Storage + accounts are placed in the specified location or affinity group. + + If the affinity group does not exist, the script will create it, optionally prompting the user for the location + in which to place the group. If an account the script is trying to create already exists, an informational + message will be displayed and progress will continue. +.EXAMPLE + New-Cloud-Service-Storage-Accounts.ps1 -CloudServiceName "MyCloudServiceName" -AffinityGroup "MyAffinityGroup" + +#> +function New-Cloud-Service-Storage-Accounts +{ + Param( + + # Cloud service name for which we're creating storage accounts + [Parameter(Mandatory=$true)] + [String]$CloudServiceName, + + # affinity group storage account will be associated with + [Parameter(ParameterSetName='ParameterSetAffinityGroup')] + [String]$AffinityGroup, + + # location/sub-region storage account will be associated with + [Parameter(ParameterSetName='ParameterSetLocation')] + [String]$Location, + + #storage account description (optional) + [String]$Description = "modified via powershell", + + # storage account label (optional) + [string]$Label + ) + + + + # The script has been tested on Powershell 3.0 + Set-StrictMode -Version 3 + + # Following modifies the Write-Verbose behavior to turn the messages on globally for this session + $VerbosePreference = "Continue" + + # Check if Windows Azure Powershell is avaiable + if ((Get-Module -ListAvailable Azure) -eq $null) + { + throw "Windows Azure Powershell not found! Please make sure to install them from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" + } + + + <# + .SYNOPSIS + Adds a new affinity group if it does not exist. + .DESCRIPTION + Looks up the current subscription's (as set by Set-AzureSubscription cmdlet) affinity groups and + creates a new affinity group if it does not exist. + .EXAMPLE + New-AzureAffinityGroupIfNotExists -AffinityGroupNme newAffinityGroup -Locstion "West US" + #> + function New-AzureAffinityGroupIfNotExists + { + param + ( + # Name of the affinity group + [Parameter(Mandatory = $true)] + [String] + $AffinityGroupName, + + # Location where the affinity group will be pointing to + [Parameter(Mandatory = $true)] + [String] + $Location) + + $affinityGroup = Get-AzureAffinityGroup -Name $AffinityGroupName -ErrorAction SilentlyContinue + if ($affinityGroup -eq $null) + { + New-AzureAffinityGroup -Name $AffinityGroupName -Location $Location -Label $AffinityGroupName ` + -ErrorVariable lastError -ErrorAction SilentlyContinue | Out-Null + if (!($?)) + { + throw "Cannot create the affinity group $AffinityGroupName on $Location" + } + Write-Verbose "Created affinity group $AffinityGroupName" + } + else + { + if ($affinityGroup.Location -ne $Location) + { + Write-Warning "Affinity group with name $AffinityGroupName already exists but in location + $affinityGroup.Location, not in $Location" + } + } + } + + <# + .SYNOPSIS + Creates a storage account + .DESCRIPTION + Creates a storage account in the specified affinity group or location if it + doesn't already exist. + .EXAMPLE + Create-Storage-Account -StorageAccountName "MyStorageAccountName" -LocationType "Location" -Location "West US" + #> + function Create-Storage-Account + { + param( + # name of storage account to be created + [Parameter(Mandatory = $true)] + [String]$StorageAccountName, + + # either "Location" or "Affinity Group" + [Parameter(Mandatory = $true)] + [String]$LocationType, + + # The location or affinity group where the storage account is to be created + [Parameter(Mandatory = $true)] + [String]$Location, + + # optional storage account description name + [String]$Description, + + # optional label to be used on the storage account + [String]$Label + ) + + # Get the directory of the current script + $scriptPath = Split-Path -parent $PSCommandPath + + # Create a new cloud service + Write-Verbose ("[Start] creating data storage account '{0}' in {1} '{2}'" ` + -f $StorageAccountName, $LocationType, $Location) + + $storageAccount = Get-AzureStorageAccount -StorageAccountName $StorageAccountName ` + -ErrorAction SilentlyContinue + # public string ServiceName { get; set; } + # public StorageServiceKeys StorageServiceKeys { get; set; } + if ($storageAccount -eq $null) + { + # Create a new storage account + If ($LocationType -eq "Location") # if affinity group was provided + { + New-AzureStorageAccount -StorageAccountName $StorageAccountName ` + -Location $Location -Description $Description ` + -ErrorVariable lastError -ErrorAction SilentlyContinue | Out-Null + if (!($?)) + { + throw "Cannot create the storage account '{0}' in affinity group '{1}'" -f $StorageAccountName, $Location + } + } + else + { + New-AzureStorageAccount -StorageAccountName $StorageAccountName ` + -AffinityGroup $Location -Description $Description ` + -ErrorVariable lastError -ErrorAction SilentlyContinue | Out-Null + if (!($?)) + { + throw "Cannot create the storage account '{0}' at location '{1}'" -f $StorageAccountName, $Location + } + } + } + else + { + Write-Verbose ("[Warning] storage account '{0}' already exists" -f $StorageAccountName) + } + + Write-Verbose ("[Finish] creating data storage account '{0}' in {1} '{2}'" ` + -f $StorageAccountName, $LocationType, $Location) + + $storageAccountKeys = Get-AzureStorageKey -StorageAccountName $StorageAccountName + Return @{ + storageAccountKeys = $storageAccountKeys; ` + } + } + + $VerbosePreference = "Continue" + $ErrorActionPreference = "Stop" + + # Mark the start time of the script execution + $startTime = Get-Date + + Write-Verbose ("[Start] creating storage accounts for cloud service {0}" -f $CloudServiceName) + + # Define the names of storage accounts + $CloudServiceName = $CloudServiceName.ToLower() + $StorageAccountName = "{0}storage" -f $CloudServiceName + + # Define verbiage text + $LocationType = "Location" + If ($AffinityGroup) # if affinity group was provided, set location type text and location variable + { + $LocationType = "Affinity Group" + $Location = $AffinityGroup + New-AzureAffinityGroupIfNotExists -AffinityGroupName $AffinityGroup + } + + # Create stoage account for data + $StorageAccountName = "{0}data" -f $CloudServiceName + $dataStorageKeys = Create-Storage-Account -StorageAccountName $StorageAccountName ` + -LocationType $LocationType -Location $Location -Description $Description -Label $Label + + # Create stoage account for diagnostics + $StorageAccountName = "{0}diag" -f $CloudServiceName + $diagStorageKeys = Create-Storage-Account -StorageAccountName $StorageAccountName ` + -LocationType $LocationType -Location $Location -Description $Description + + Write-Verbose ("[Finish] creating Windows Azure cloud service storage accounts") + + # retrieve storage account information return as variables so we can use it. + + # Mark the finish time of the script execution + $finishTime = Get-Date + # Output the time consumed in seconds + Write-Output ("Total time used (seconds): {0}" -f ($finishTime - $startTime).TotalSeconds) + + Return @{ + # need to return storage names and keys as hash table + dataStorageKeys = $dataStorageKeys; ` + diagStorageKeys = $diagStorageKeys; ` + } + +} \ No newline at end of file diff --git a/services/virtual-machines/Get-LatestImage.ps1 b/services/virtual-machines/Get-LatestImage.ps1 new file mode 100644 index 0000000..154f10b --- /dev/null +++ b/services/virtual-machines/Get-LatestImage.ps1 @@ -0,0 +1,62 @@ +<# +.SYNOPSIS + Returns the latest image for a given image family name filter. +.DESCRIPTION + Will return the latest image based on a filter match on the ImageFamilyName and + PublisedDate of the image. The more specific the filter, the more control you have + over the object returned. +.EXAMPLE + The following example will return the latest SQL Server image. It could be SQL Server + 2014, 2012 or 2008 + + Get-LatestImage -ImageFamilyNameFilter "*SQL Server*" + + The following example will return the latest SQL Server 2014 image. This function will + also only select the image from images published by Microsoft. + + Get-LatestImage -ImageFamilyNameFilter "*SQL Server 2014*" -OnlyMicrosoftImages + + The following example will return $null because Microsoft doesn't publish Ubuntu images. + + Get-LatestImage -ImageFamilyNameFilter "*Ubuntu*" -OnlyMicrosoftImages +#> +function Get-LatestImage +{ + param + ( + # A filter for selecting the image family. + # For example, "Windows Server 2012*", "*2012 Datacenter*", "*SQL*, "Sharepoint*" + [Parameter(Mandatory = $true)] + [String] + $ImageFamilyNameFilter, + + # A switch to indicate whether or not to select the latest image where the publisher is Microsoft. + # If this switch is not specified, then images from all possible publishers are considered. + [Parameter(Mandatory = $false)] + [switch] + $OnlyMicrosoftImages + ) + + # Get a list of all available images. + $imageList = Get-AzureVMImage + + if ($OnlyMicrosoftImages.IsPresent) + { + $imageList = $imageList | + Where-Object { ` + ($_.PublisherName -ilike "Microsoft*" -and ` + $_.ImageFamily -ilike $ImageFamilyNameFilter ) } + } + else + { + $imageList = $imageList | + Where-Object { ` + ($_.ImageFamily -ilike $ImageFamilyNameFilter ) } + } + + $imageList = $imageList | + Sort-Object -Unique -Descending -Property ImageFamily | + Sort-Object -Descending -Property PublishedDate + + $imageList | Select-Object -First(1) +} diff --git a/services/virtual-machines/InstallWinRMCertificate.ps1 b/services/virtual-machines/InstallWinRMCertificate.ps1 new file mode 100644 index 0000000..cf0189c --- /dev/null +++ b/services/virtual-machines/InstallWinRMCertificate.ps1 @@ -0,0 +1,34 @@ +<# +.Synopsis + Installs a WinRm certificate to the local store +.DESCRIPTION + Gets the WinRM certificate from the Virtual Machine in the Service Name specified, and + installs it on the Current User's personal store. +.EXAMPLE + Install-WinRmCertificate -ServiceName testservice -vmName testVm +.INPUTS + None +.OUTPUTS + Microsoft.WindowsAzure.Management.ServiceManagement.Model.OSImageContext +#> +function Install-WinRmCertificate($ServiceName, $VMName) +{ + $vm = Get-AzureVM -ServiceName $ServiceName -Name $VMName + $winRmCertificateThumbprint = $vm.VM.DefaultWinRMCertificateThumbprint + + $winRmCertificate = Get-AzureCertificate -ServiceName $ServiceName -Thumbprint $winRmCertificateThumbprint -ThumbprintAlgorithm sha1 + + $installedCert = Get-Item Cert:\CurrentUser\My\$winRmCertificateThumbprint -ErrorAction SilentlyContinue + + if ($installedCert -eq $null) + { + $certBytes = [System.Convert]::FromBase64String($winRmCertificate.Data) + $x509Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate + $x509Cert.Import($certBytes) + + $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root", "LocalMachine" + $store.Open("ReadWrite") + $store.Add($x509Cert) + $store.Close() + } +} diff --git a/services/virtual-machines/Send-File.ps1 b/services/virtual-machines/Send-File.ps1 new file mode 100644 index 0000000..63fd1e8 --- /dev/null +++ b/services/virtual-machines/Send-File.ps1 @@ -0,0 +1,85 @@ +<# +.SYNOPSIS + Sends a file to a remote session. +.EXAMPLE + $remoteSession = New-PSSession -ConnectionUri $remoteWinRmUri.AbsoluteUri -Credential $credential + Send-File -Source "c:\temp\myappdata.xml" -Destination "c:\temp\myappdata.xml" $remoteSession +#> +function Send-File +{ + param( + ## The path on the local computer + [Parameter(Mandatory = $true)] + $Source, + + ## The target path on the remote computer + [Parameter(Mandatory = $true)] + $Destination, + + ## The session that represents the remote computer + [Parameter(Mandatory = $true)] + [System.Management.Automation.Runspaces.PSSession] $Session) + + Set-StrictMode -Version 3 + + $remoteScript = { + param($destination, $bytes) + + ## Convert the destination path to a full filesystem path (to support + ## relative paths) + $Destination = $executionContext.SessionState.` + Path.GetUnresolvedProviderPathFromPSPath($Destination) + + ## Write the content to the new file + $file = [IO.File]::Open($Destination, "OpenOrCreate") + $null = $file.Seek(0, "End") + $null = $file.Write($bytes, 0, $bytes.Length) + $file.Close() + } + + ## Get the source file, and then start reading its content + $sourceFile = Get-Item $source + + ## Delete the previously-existing file if it exists + Invoke-Command -Session $session { + if(Test-Path $args[0]) { Remove-Item $args[0] } + } -ArgumentList $Destination + + ## Now break it into chunks to stream + Write-Progress -Activity "Sending $Source" -Status "Preparing file" + $streamSize = 1MB + $position = 0 + $rawBytes = New-Object byte[] $streamSize + $file = [IO.File]::OpenRead($sourceFile.FullName) + while(($read = $file.Read($rawBytes, 0, $streamSize)) -gt 0) + { + Write-Progress -Activity "Writing $Destination" ` + -Status "Sending file" ` + -PercentComplete ($position / $sourceFile.Length * 100) + + ## Ensure that our array is the same size as what we read + ## from disk + if($read -ne $rawBytes.Length) + { + [Array]::Resize( [ref] $rawBytes, $read) + } + + ## And send that array to the remote system + Invoke-Command -Session $session $remoteScript ` + -ArgumentList $destination,$rawBytes + + ## Ensure that our array is the same size as what we read + ## from disk + if($rawBytes.Length -ne $streamSize) + { + [Array]::Resize( [ref] $rawBytes, $streamSize) + } + [GC]::Collect() + $position += $read + } + + $file.Close() + + ## Show the result + Invoke-Command -Session $session { Get-Item $args[0] } -ArgumentList $Destination +} \ No newline at end of file diff --git a/services/virtual-machines/place-holder.txt b/services/virtual-machines/place-holder.txt deleted file mode 100644 index e69de29..0000000 diff --git a/solutions/big-data/New-HDInsightCluster.ps1 b/solutions/big-data/New-HDInsightCluster.ps1 new file mode 100644 index 0000000..dba1e49 --- /dev/null +++ b/solutions/big-data/New-HDInsightCluster.ps1 @@ -0,0 +1,158 @@ +<# +.SYNOPSIS + Creates a cluster with specified configuration. +.DESCRIPTION + Creates a HDInsight cluster configured with one storage account and default metastores. User is prompted for credentials to use to provision the cluster. + The provisioning operation usually takes around 15 minutes. + + Note: This script requires an Azure HDInsight cmdlets to be installed on the machine in addition to Azure PowerShell Tools. Azure HDInsight cmdlets can be + installed according to the instructions here: https://hadoopsdk.codeplex.com/wikipage?title=PowerShell%20Cmdlets%20for%20Cluster%20Management + + Note: Current version of the script expects storage container to exist. + +.EXAMPLE + .\New-HDInsightCluster.ps1 -Cluster "MyClusterName" -Location "North Europe" ` + -DefaultStorageAccount mystorage -DefaultStorageContainer myContainer ` + -ClusterSizeInNodes 4 +#> + +param ( + # Cluster dns name to create + [Parameter(Mandatory = $true)] + [String]$Cluster, + + # Location + [Parameter(Mandatory = $true)] + [String]$Location, + + # Blob storage account that new cluster will be connected to + [Parameter(Mandatory = $false)] + [String]$DefaultStorageAccount = "", + + # Blob storage container that new cluster will use by default + [Parameter(Mandatory = $false)] + [String]$DefaultStorageContainer = "", + + # Number of data nodes that will be provisioned in the new cluster + [Parameter(Mandatory = $false)] + [Int32]$ClusterSizeInNodes = 2, + + # Optional credentials parameter to be used for the new cluster + [Parameter(Mandatory = $false)] + [PSCredential]$Credential = $null) + + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please make sure to install them from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + +# Check if HDInsight Powershell is avaiable +$module = Get-Module -Name Microsoft.WindowsAzure.Management.HDInsight.Cmdlet +if ($module -eq $null) +{ + throw "HDInsight Powershell module not found! Please make sure to install them from https://hadoopsdk.codeplex.com/wikipage?title=PowerShell%20Cmdlets%20for%20Cluster%20Management" +} + +# Get the current subscription +$subid = Get-AzureSubscription -Current | %{ $_.SubscriptionId } +$cert = Get-AzureSubscription -Current | %{ $_.Certificate } + +# Create storage account and container if not specified +if ($DefaultStorageAccount -eq "") { + $DefaultStorageAccount = $Cluster.ToLowerInvariant() + + # Check if account already exists then use it + $storageAccount = Get-AzureStorageAccount -StorageAccountName $DefaultStorageAccount -ErrorAction SilentlyContinue + if ($storageAccount -eq $null) { + Write-Verbose "Creating new storage account $DefaultStorageAccount." + $storageAccount = New-AzureStorageAccount –StorageAccountName $DefaultStorageAccount -Location $Location + } else { + Write-Verbose "Using existing storage account $DefaultStorageAccount." + } +} + +# Check if container already exists then use it +if ($DefaultStorageContainer -eq "") { + $storageContext = New-AzureStorageContext –StorageAccountName $DefaultStorageAccount -StorageAccountKey (Get-AzureStorageKey $DefaultStorageAccount).Primary + + $DefaultStorageContainer = $DefaultStorageAccount + $storageContainer = Get-AzureStorageContainer -Name $DefaultStorageContainer -Context $storageContext -ErrorAction SilentlyContinue + if ($storageContainer -eq $null) { + Write-Verbose "Creating new storage container $DefaultStorageContainer." + $storageContainer = New-AzureStorageContainer -Name $DefaultStorageContainer -Context $storageContext + } else { + Write-Verbose "Using existing storage container $DefaultStorageContainer." + } +} + +if ($Credential -eq $null) { + # Get user credentials to use when provisioning the cluster. + Write-Verbose "Prompt user for administrator credentials to use when provisioning the cluster." + $credential = Get-Credential + Write-Verbose "Administrator credentials captured. Use these credentials to login to the cluster when the script is complete." +} + +# Initiate cluster provisioning +$userName = $credential.GetNetworkCredential().UserName +$password = $credential.GetNetworkCredential().Password + +$storage = Get-AzureStorageAccount $DefaultStorageAccount + +$provJob = Start-Job –Scriptblock { + param( + $subid, + $cert, + $Cluster, + $Location, + $storage, + $DefaultStorageAccount, + $DefaultStorageContainer, + $userName, + $password, + $ClusterSizeInNodes, + $modulePath + ) + Import-Module $modulePath + $cert = Get-AzureSubscription -Current | %{ $_.Certificate } + New-AzureHDInsightCluster -SubscriptionId $subid -Certificate $cert -Name $Cluster -Location $Location ` + -DefaultStorageAccountName ($storage.StorageAccountName + ".blob.core.windows.net") ` + -DefaultStorageAccountKey (Get-AzureStorageKey $DefaultStorageAccount).Primary ` + -DefaultStorageContainerName $DefaultStorageContainer ` + -UserName $userName -Password $password ` + -ClusterSizeInNodes $ClusterSizeInNodes +} -Arg @(` + $subid,` + $cert,` + $Cluster,` + $Location,` + $storage,` + $DefaultStorageAccount,` + $DefaultStorageContainer,` + $userName,` + $password,` + $ClusterSizeInNodes,` + $module.Path) + +Write-Host "Sending request to provision cluster $Cluster" + +# Poll and report status of the cluster during the provisioning process +$state = "" +while($provJob.State -ne "Completed" -and $state -ne "Running") { + Start-Sleep -s 5; + $clusterObj = (Get-AzureHDInsightCluster -SubscriptionId $subid -Certificate $cert -Name $Cluster) + if ($clusterObj.State -ne $state -and $clusterObj.State -ne $null -and $clusterObj.State -ne "") { + $state = $clusterObj.State + Write-Host ("Status: " + $clusterObj.State) + } +} + +# Report errors from the background job if any +Receive-Job $provJob diff --git a/solutions/big-data/readme.md b/solutions/big-data/readme.md new file mode 100644 index 0000000..6c3e25e --- /dev/null +++ b/solutions/big-data/readme.md @@ -0,0 +1,17 @@ +# New-HDInsightCluster +## Description ## +Creates a HDInsight cluster configured with one storage account and default metastores. User is prompted for credentials to use to provision the cluster. During the provisioning operation which usually takes around 15 minutes the script monitors status and report when cluster is transitioning through the provisioning states. + +**Note:** This script requires an Azure HDInsight cmdlets to be installed on the machine in addition to Azure PowerShell Tools. Azure HDInsight cmdlets can be installed according to the instructions here: https://hadoopsdk.codeplex.com/wikipage?title=PowerShell%20Cmdlets%20for%20Cluster%20Management + +**Note:** Current version of the script expects storage container to exist. + +## Scenario ## +You want to provision a Hadoop cluster in default configuration and connected to single storage account. +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 +- Windows Azure HDInsight PowerShell + +## See Also ## +- Set-AzureSubscription \ No newline at end of file diff --git a/solutions/data-management/CalculateBlobCost.ps1 b/solutions/data-management/CalculateBlobCost.ps1 new file mode 100644 index 0000000..3d1defe --- /dev/null +++ b/solutions/data-management/CalculateBlobCost.ps1 @@ -0,0 +1,172 @@ +<# +.SYNOPSIS + Calculates cost of all blobs in a container or storage account. +.DESCRIPTION + Enumerates all blobs in either one container or one storage account and sums + up all costs associated. This includes all block and page blobs, all metadata + on either blobs or containers. It also includes both committed and uncommitted + blocks in the case that a blob is partially uploaded. + + The details of the calculations can be found in this post: + http://blogs.msdn.com/b/windowsazurestorage/archive/2010/07/09/understanding-windows-azure-storage-billing-bandwidth-transactions-and-capacity.aspx + + Note: This script requires an Azure Storage Account to run. The storage account + can be specified by setting the subscription configuration. For example: + Set-AzureSubscription -SubscriptionName "MySubscription" -CurrentStorageAccount "MyStorageAccount" +.EXAMPLE + .\CalculateBlobCost.ps1 -StorageAccountName "mystorageaccountname" + .\CalculateBlobCost.ps1 -StorageAccountName "mystorageaccountname" -ContainerName "mycontainername" +#> + +param( + # The name of the storage account to enumerate. + [Parameter(Mandatory = $true)] + [string]$StorageAccountName, + + # The name of the storage container to enumerate. + [Parameter(Mandatory = $false)] + [ValidateNotNullOrEmpty()] + [string]$ContainerName +) + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + +<# +.SYNOPSIS + Gets the size (in bytes) of a blob. +.DESCRIPTION + Given a blob name, sum up all bytes consumed including the blob itself and any metadata, + all committed blocks and uncommitted blocks. + + Formula reference for calculating size of blob: + http://blogs.msdn.com/b/windowsazurestorage/archive/2010/07/09/understanding-windows-azure-storage-billing-bandwidth-transactions-and-capacity.aspx +.INPUTS + $Blob - The blob to calculate the size of. +.OUTPUTS + $blobSizeInBytes - The calculated sizeo of the blob. +#> +function Get-BlobBytes +{ + param ( + [Parameter(Mandatory=$true)] + [Microsoft.WindowsAzure.Management.Storage.Model.ResourceModel.AzureStorageBlob]$Blob) + + # Base + blob name + $blobSizeInBytes = 124 + $Blob.Name.Length * 2 + + # Get size of metadata + $metadataEnumerator = $Blob.ICloudBlob.Metadata.GetEnumerator() + while ($metadataEnumerator.MoveNext()) + { + $blobSizeInBytes += 3 + $metadataEnumerator.Current.Key.Length + $metadataEnumerator.Current.Value.Length + } + + if ($Blob.BlobType -eq [Microsoft.WindowsAzure.Storage.Blob.BlobType]::BlockBlob) + { + $blobSizeInBytes += 8 + $Blob.ICloudBlob.DownloadBlockList() | + ForEach-Object { $blobSizeInBytes += $_.Length + $_.Name.Length } + } + else + { + $Blob.ICloudBlob.GetPageRanges() | + ForEach-Object { $blobSizeInBytes += 12 + $_.EndOffset - $_.StartOffset } + } + + return $blobSizeInBytes +} + +<# +.SYNOPSIS + Gets the size (in bytes) of a blob container. +.DESCRIPTION + Given a container name, sum up all bytes consumed including the container itself and any metadata, + all blobs in the container together with metadata, all committed blocks and uncommitted blocks. +.INPUTS + $Container - The container to calculate the size of. +.OUTPUTS + $containerSizeInBytes - The calculated size of the container. +#> +function Get-ContainerBytes +{ + param ( + [Parameter(Mandatory=$true)] + [Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer]$Container) + + # Base + name of container + $containerSizeInBytes = 48 + $Container.Name.Length * 2 + + # Get size of metadata + $metadataEnumerator = $Container.Metadata.GetEnumerator() + while ($metadataEnumerator.MoveNext()) + { + $containerSizeInBytes += 3 + $metadataEnumerator.Current.Key.Length + + $metadataEnumerator.Current.Value.Length + } + + # Get size for Shared Access Policies + $containerSizeInBytes += $Container.GetPermissions().SharedAccessPolicies.Count * 512 + + # Calculate size of all blobs. + $blobCount = 0 + Get-AzureStorageBlob -Context $storageContext -Container $Container.Name | + ForEach-Object { + $containerSizeInBytes += Get-BlobBytes $_ + $blobCount++ + } + + return @{ "containerSize" = $containerSizeInBytes; "blobCount" = $blobCount } +} + +$storageAccount = Get-AzureStorageAccount -StorageAccountName $StorageAccountName -ErrorAction SilentlyContinue +if ($storageAccount -eq $null) +{ + throw "The storage account specified does not exist in this subscription." +} + +# Instantiate a storage context for the storage account. +$storagePrimaryKey = (Get-AzureStorageKey -StorageAccountName $StorageAccountName).Primary +$storageContext = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $storagePrimaryKey + +# Get a list of containers to process. +$containers = New-Object System.Collections.ArrayList +if ($ContainerName.Length -ne 0) +{ + $container = Get-AzureStorageContainer -Context $storageContext ` + -Name $ContainerName -ErrorAction SilentlyContinue | + ForEach-Object { $containers.Add($_) } | Out-Null +} +else +{ + Get-AzureStorageContainer -Context $storageContext | ForEach-Object { $containers.Add($_) } | Out-Null +} + +# Calculate size. +$sizeInBytes = 0 +if ($containers.Count -gt 0) +{ + $containers | ForEach-Object { + $result = Get-ContainerBytes $_.CloudBlobContainer + $sizeInBytes += $result.containerSize + Write-Verbose ("Container '{0}' with {1} blobs has a size of {2:F2}MB." -f ` + $_.CloudBlobContainer.Name, $result.blobCount, ($result.containerSize / 1MB)) + } + Write-Output ("Total size calculated for {0} containers is {1:F2}GB." -f $containers.Count, ($sizeInBytes / 1GB)) + + # Launch default browser to azure calculator for data management. + Start-Process -FilePath http://www.windowsazure.com/en-us/pricing/calculator/?scenario=data-management +} +else +{ + Write-Warning "No containers found to process in storage account '$StorageAccountName'." +} diff --git a/solutions/data-management/CopyAllVhdBetweenSubscription.ps1 b/solutions/data-management/CopyAllVhdBetweenSubscription.ps1 new file mode 100644 index 0000000..ba8a035 --- /dev/null +++ b/solutions/data-management/CopyAllVhdBetweenSubscription.ps1 @@ -0,0 +1,150 @@ +<# +.SYNOPSIS + Copy all Virtual Hard Disks (VHD's) from the current subscription to a different + subscription. +.DESCRIPTION + Start's an asynchronous copy of VHD's to a different subscription and storage account. +.EXAMPLE + .\CopyAllVhdBetweenSubscription.ps1 + -DestContainerName "DestinationContainerName" + -DestStorageAccountName "DestinationStorageAccount" + -DestStorageAccountKey "DestinationStorageKey" +#> +param +( + # Destination Storage Container name + [Parameter(Mandatory = $true)] + [String]$DestContainerName, + + # Destination Storage Account name + [Parameter(Mandatory = $true)] + [String]$DestStorageAccountName, + + # Destination Storage Account Key + [Parameter(Mandatory = $true)] + [String]$DestStorageAccountKey) + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + +# Get a collection of all disks. +$azureDisks = Get-AzureDisk + +$tempStorageContainerAccounts = @{} +# Copy each VHD in the current storage account to a temporary container. +$tempStorageContainerName = "pstmp" + [DateTime]::UtcNow.Ticks +$tempCopyStates = @() +foreach ($azureDisk in $azureDisks) +{ + $src = $azureDisk.MediaLink + $vhdName = $azureDisk.MediaLink.Segments | Where-Object { $_ -like "*.vhd" } + + if ($vhdName -ne $null) + { + $srcStorageAccount = $src.Host.Replace(".blob.core.windows.net", "") + $srcStorageAccountKey = (Get-AzureStorageKey -StorageAccountName $srcStorageAccount).Primary + + $srcContext = New-AzureStorageContext -StorageAccountName $srcStorageAccount -StorageAccountKey $srcStorageAccountKey + if ((Get-AzureStorageContainer -Name $tempStorageContainerName -Context $srcContext -ErrorAction SilentlyContinue) -eq $null) + { + Write-Verbose "Creating container '$tempStorageContainerName'." + New-AzureStorageContainer -Name $tempStorageContainerName -Context $srcContext + } + + # Schedule a blob copy operation + $tempCopyState = Start-AzureStorageBlobCopy -Context $srcContext -SrcUri $src ` + -DestContext $srcContext -DestContainer $tempStorageContainerName ` + -DestBlob $vhdName + $tempCopyStates += $tempCopyState + + # Add the storage account and context to a hash table so + # these can be removed at the end. + if (($tempStorageContainerAccounts[$srcStorageAccount]) -eq $null) + { + $tempStorageContainerAccounts[$srcStorageAccount] = $srcContext + } + } +} + +# Wait for all copy operations to temporary container to complete +# These copies should be instantaneous since they are in the same data center. +foreach ($copyState in $tempCopyStates) +{ + # Show copy status. + $copyState | + Get-AzureStorageBlobCopyState -WaitForComplete | + Format-Table -AutoSize -Property Status,BytesCopied,TotalBytes,Source +} + + +# Make sure destination container exists. Create if it does not. +$destContext = New-AzureStorageContext –StorageAccountName $DestStorageAccountName -StorageAccountKey $DestStorageAccountKey +if ((Get-AzureStorageContainer -Name $DestContainerName -Context $destContext -ErrorAction SilentlyContinue) -eq $null) +{ + Write-Verbose ("Creating container '{0}' in destination storage account '{1}'." -f $DestContainerName, $DestStorageAccountName) + New-AzureStorageContainer -Name $DestContainerName -Context $destContext +} + +# Copy blobs to destination storage account. +$destCopyStates = @() +foreach ($item in $tempStorageContainerAccounts.GetEnumerator()) +{ + $srcContext = $item.Value + Get-AzureStorageBlob -Container $tempStorageContainerName -Context $srcContext | + ForEach-Object { + $blob = $_ + $blobUri = $_.ICloudBlob.Container.Uri.AbsoluteUri + "/" + ($blob.Name) + + # Schedule a blob copy operation to the destination account. + $destCopyState = Start-AzureStorageBlobCopy -Context $srcContext -SrcUri $blobUri ` + -DestContext $destContext -DestContainer $DestContainerName ` + -DestBlob $blob.Name -Force + $destCopyStates += $destCopyState + } +} + +# Show the status of each blob copy operation. +# This could take a while if copying across data centers. +$delaySeconds = 10 +do +{ + Write-Verbose "Checking storage blob copy status every $delaySeconds seconds." + Write-Verbose "This will repeat until all copy operations are complete." + Write-Verbose "Press Ctrl-C anytime to stop checking status." + Write-Warning "If you do press Ctrl-C, manually remove temporary container '$tempStorageContainerName' from your storage accounts after the copy operation completes." + Start-Sleep $delaySeconds + + $continue = $false + + foreach ($copyState in $destCopyStates) + { + # Check the copy state for each blob. + $copyStatus = $copyState | Get-AzureStorageBlobCopyState + $copyStatus | Format-Table -AutoSize -Property Status,BytesCopied,TotalBytes,Source + + # Continue checking status as long as at least one operations is still pending. + if (!$continue) + { + $continue = $copyStatus -eq [Microsoft.WindowsAzure.Storage.Blob.CopyStatus]::Pending + } + } +} while ($continue) + + +# Remove temporary storage containers +foreach ($item in $tempStorageContainerAccounts.GetEnumerator()) +{ + Write-Verbose ("Removing container '{0}' from storage account '{1}'." -f $tempStorageContainerName, $item.Key) + Remove-AzureStorageContainer -Name $tempStorageContainerName -Context ($item.Value) -Force +} + + diff --git a/solutions/data-management/CopyFilesFromAzureStorageContainer.ps1 b/solutions/data-management/CopyFilesFromAzureStorageContainer.ps1 new file mode 100644 index 0000000..1885fbb --- /dev/null +++ b/solutions/data-management/CopyFilesFromAzureStorageContainer.ps1 @@ -0,0 +1,142 @@ +<# +.SYNOPSIS + Copies files from a storage container to a local folder. +.DESCRIPTION + Copies blobs from a single storage container or all storage containers to a local + directory. If the blobs have "/" in the name to represent a directory hierarchy, + then the script will recreate that directory hierarchy under the local destination + path specified. + + The script supports the -Whatif switch so you can quickly see how complex the copy + operation would be. + + Note: This script requires an Azure Storage Account to run. The storage account + can be specified by setting the subscription configuration. For example: + Set-AzureSubscription -SubscriptionName "MySubscription" -CurrentStorageAccount "MyStorageAccount" +.EXAMPLE + .\CopyFilesFromAzureStorageContainer -LocalPath "c:\users\\documents" ` + -StorageContainer "myuserdocuments" +#> +[CmdletBinding(SupportsShouldProcess = $true)] +param( + # The destination path to copy files to. + [Parameter(Mandatory = $true)] + [string]$LocalPath, + + # The name of the storage container to copy files from. + # This parameter is ignored if -All is specified. + [Parameter(Mandatory = $false)] + [string]$StorageContainer, + + # If specified, will download all containers. + [Parameter(Mandatory = $false)] + [switch]$All, + + # If specified, will create the destination path. + [Parameter(Mandatory = $false)] + [switch]$CreateLocalPath, + + # If specified, will overwrite existing files in the destination path. + [Parameter(Mandatory = $false)] + [switch]$Force +) + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + +<# +.SYNOPSIS + Downloads all blobs in a container to a local file path. +.DESCRIPTION + A subdirectory is created in the local path given matching the container name. + All blobs in the container are copied to the subdirectory. +.EXAMPLE + DownloadContainer -StoraceContainerName "conatinername" -DestLocalPath "c:\Temp" +#> +function DownloadContainer +{ + param( + # The name of storage container to copy. + [Parameter(Mandatory = $true)] + [string]$SourceContainerName, + + # The destination local path to copy to. + [Parameter(Mandatory = $true)] + $DestLocalPath) + + # Get a reference to the container. + $container = Get-AzureStorageContainer -Name $SourceContainerName -ErrorAction SilentlyContinue + if ($container -eq $null) + { + throw "Unable to reach storage container '$SourceContainerName'." + } + + # Copy blobs from storage container to local file path. + $blobs = Get-AzureStorageBlob -Container $SourceContainerName + foreach ($blob in $blobs) + { + $sourceBlob = $SourceContainerName + "\" + $blob.Name + $destFilePath = $DestLocalPath + "\" + $blob.Name + + # Create a sub-directory using the container name. + $destDirectory = [System.IO.Path]::GetDirectoryName($destFilePath) + $destFilePath = $destDirectory + "\" + [System.IO.Path]::GetFileName($destFilePath) + if (-not (Test-Path $destDirectory -PathType Container)) + { + New-Item -Path $destDirectory -ItemType Directory + } + + # Copy blob from container to local path. + if ($PSCmdlet.ShouldProcess($destFilePath, "Copy File")) + { + Get-AzureStorageBlobContent ` + -Container $SourceContainerName -Blob $blob.Name -Destination $destFilePath | ` + Format-Table -Property Length,Name -AutoSize + } + } +} + +# Ensure the local path given exists. Create it if switch specified to do so. +if (-not (Test-Path $LocalPath)) +{ + if ($CreateLocalPath.IsPresent) + { + New-Item -Path $LocalPath -ItemType Directory + } + else + { + throw "Path '$LocalPath' does not exist. Specify an existing path or provide the CreateLocalPath switch to create it." + } +} + +$localContainerPath = "" +if ($All.IsPresent) +{ + # Enumerate through all containers and download blobs for each one. + $containers = Get-AzureStorageContainer + foreach ($container in $containers) + { + $localContainerPath = $LocalPath + "\" + $container.Name + DownloadContainer -SourceContainerName $container.Name -DestLocalPath $localContainerPath + } + +} +elseif ($StorageContainer -ne $null -and $StorageContainer -ne "" ) +{ + # Download blobs for the specified container. + $localContainerPath = $LocalPath + "\" + $StorageContainer + DownloadContainer -SourceContainerName $StorageContainer -DestLocalPath $localContainerPath +} +else +{ + throw "Provide a valid storage container name using the 'StorageContainer' parameter or include the -All switch to copy all containers." +} diff --git a/solutions/data-management/CopyFilesToAzureStorageContainer.ps1 b/solutions/data-management/CopyFilesToAzureStorageContainer.ps1 new file mode 100644 index 0000000..41de05a --- /dev/null +++ b/solutions/data-management/CopyFilesToAzureStorageContainer.ps1 @@ -0,0 +1,143 @@ +<# +.SYNOPSIS + Copies files from a local folder to an Azure blob storage container. +.DESCRIPTION + Copies files (in parallel) from a local folder to a named Azure storage + blob container. The copy operation can optionally recurse the local folder + using the -Recurse switch. The storage container is assumed to already exist + unless the -CreateContainer switch is provided. + + Note: This script requires an Azure Storage Account to run. The storage account + can be specified by setting the subscription configuration. For example: + Set-AzureSubscription -SubscriptionName "MySubscription" -CurrentStorageAccount "MyStorageAccount" +.EXAMPLE + .\CopyFilesToAzureStorageContainer -LocalPath "c:\users\\documents" ` + -StorageContainer "myuserdocuments" -Recurse -CreateStorageContainer +#> + +[CmdletBinding(SupportsShouldProcess = $true)] +param( + # The full path to copy files from. + [Parameter(Mandatory = $true)] + [string]$LocalPath, + + # The name of the storage container to copy files to. + [Parameter(Mandatory = $true)] + [string]$StorageContainer, + + # If specified, will recurse the LocalPath specified. + [Parameter(Mandatory = $false)] + [switch]$RecurseLocalPath, + + # If specified, will create the storage container. + [Parameter(Mandatory = $false)] + [switch]$CreateStorageContainer, + + # If specified, will copy files to the container if the container already exists. + [Parameter(Mandatory = $false)] + [switch]$Force +) + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + +workflow UploadFilesInParallel +{ + param( + # The name of the storage container to copy files to. + [Parameter(Mandatory = $true)] + [string]$StorageContainer, + + # An array of files to copy to the storage container. + [Parameter(Mandatory = $true)] + [System.Object[]]$Files + ) + + if ($Files.Count -gt 0) + { + foreach -parallel ($file in $Files) + { + $blobFileName = Split-Path -Path $file.FullName -NoQualifier + try + { + Set-AzureStorageBlobContent -Container $StorageContainer ` + -File $file.FullName -Blob $blobFileName ` + -ConcurrentTaskCount 0 -Force + } + catch + { + $warningMessage = "Unable to upload file " + $file.FullName + Write-Warning -Message $warningMessage + } + } + } +} + +# Ensure the local path given exists. Create it if switch specified to do so. +if (-not (Test-Path $LocalPath -IsValid)) +{ + throw "Source path '$LocalPath' does not exist. Specify an existing path." +} + +# Get a list of files from the local folder. +if ($RecurseLocalPath.IsPresent) +{ + $files = ls -Path $LocalPath -File -Recurse +} +else +{ + $files = ls -Path $LocalPath -File +} + +if ($files -ne $null -and $files.Count -gt 0) +{ + # Create the storage container. + if ($CreateStorageContainer.IsPresent) + { + $existingContainer = Get-AzureStorageContainer | + Where-Object { $_.Name -like $StorageContainer } + + if ($existingContainer) + { + $msg = "Storage container '" + $StorageContainer + "' already exists." + if (!$Force.IsPresent -and !$PSCmdlet.ShouldContinue( + "Copy files to existing container?", $msg)) + { + throw "Specify a different storage container name." + } + } + else + { + if ($PSCmdlet.ShouldProcess($StorageContainer, "Create Container")) + { + $newContainer = New-AzureStorageContainer -Name $StorageContainer + "Storage container '" + $newContainer.Name + "' created." + } + } + } + + # Upload the files to storage container. + $fileCount = $files.Count + if ($PSCmdlet.ShouldProcess($StorageContainer, "Copy $fileCount files")) + { + $time = [DateTime]::UtcNow + UploadFilesInParallel -StorageContainer $StorageContainer -Files $files + $duration = [DateTime]::UtcNow - $time + + "Uploaded " + $files.Count + " files to blob container '" + $StorageContainer + "'." + "Total upload time: " + $duration.TotalMinutes + " minutes." + } +} +else +{ + Write-Warning "No files found." +} \ No newline at end of file diff --git a/solutions/data-management/Remove-BlobsFromAllContainers.ps1 b/solutions/data-management/Remove-BlobsFromAllContainers.ps1 new file mode 100644 index 0000000..2ebb3c4 --- /dev/null +++ b/solutions/data-management/Remove-BlobsFromAllContainers.ps1 @@ -0,0 +1,91 @@ +<# +.SYNOPSIS + Remove all blobs (including snapshots)from one storage account. +.DESCRIPTION + This script will run through a single Azure storage account and delete all blobs in + all containers including snapshots. +.EXAMPLE + .\Remove-BlobsFromAllContainers.ps1 -StorageAccountName "storageaccountname" -Force +#> + +[CmdletBinding(SupportsShouldProcess = $true)] +param( + + # StorageAccount name for BLOB deletion + [Parameter(Mandatory = $true)] + [string]$StorageAccountName, + + # If specified, will remove the containers rather than individual blobs. + [Parameter(Mandatory = $false)] + [switch]$RemoveContainer, + + # If specified, will remove blobs without prompting user to confirm. + [Parameter(Mandatory = $false)] + [switch]$Force + ) + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + +# getting Azure storage account key +$fullkeys = Get-AzureStorageKey -StorageAccountName $StorageAccountName + +# the script will be using primary key. +$key = $fullkeys[0].Primary + +# getting storage account content +$context = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $key + +$containers = Get-AzureStorageContainer -Context $context +# loop through each container and get list of blobs for each container and delete +foreach($container in $containers) +{ + if ($RemoveContainer.IsPresent) + { + if (($Force.IsPresent) -or + ($PSCmdlet.ShouldContinue( + "Remove container " + $container.Name + " and all blobs in the container?", + "Confirm Remove Operation"))) + { + Remove-AzureStorageContainer -Name $container.Name -Force + } + } + else + { + $blobsRemoved = 0 + + Write-Verbose ("Searching Container: {0}" -f $container.Name) + $blobs = Get-AzureStorageBlob -Container $container.Name -Context $context + + if ($blobs -ne $null) + { + if ($blobs.Count -gt 0) + { + if (($Force.IsPresent) -or + ($PSCmdlet.ShouldContinue( + "Remove " + $blobs.Length + " files from container " + $container.Name + "?", + "Confirm Remove Operation"))) + { + foreach ($blob in $blobs) + { + Write-Verbose ("Removing Blob: {0}" -f $blob.Name) + Remove-AzureStorageBlob -ICloudBlob $blob.ICloudBlob -Context $context + $blobsRemoved += 1 + } + } + } + } + + Write-Verbose ("{0} blobs removed from container {1}." -f $blobsRemoved, $container.Name) + } +} + diff --git a/solutions/data-management/Set-StorageServiceProperties.ps1 b/solutions/data-management/Set-StorageServiceProperties.ps1 new file mode 100644 index 0000000..57523ad --- /dev/null +++ b/solutions/data-management/Set-StorageServiceProperties.ps1 @@ -0,0 +1,145 @@ +<# +.SYNOPSIS + Turn on/off storage logging and metrics for all storage accounts under one Subscription. +.DESCRIPTION + This script will turn on/off the logging and metrics for all storage accounts under the default subscription. + You can also, provide the storage account name to restrict the action to that one. +.EXAMPLE + Enable logging and metrics for a single storage account. + .\Set-StorageServiceProperties.ps1 -StorageAccountName "StorageAccountName" -Enable + + Disable logging and metrics for all storage accounts. + .\Set-StorageServiceProperties.ps1 -Disable -All + +#> + +param( + [CmdletBinding( SupportsShouldProcess=$true)] + + # The Storage account name to enable logging and monitoring on. + [Parameter(Mandatory = $false)] + [String]$StorageAccountName, + + # Turn logging on. + [Parameter(Mandatory = $false)] + [switch]$Enable, + + # Turn logging off. + [Parameter(Mandatory = $false)] + [switch]$Disable, + + # If specfied, will enable logging and metrice for all storage accounts in the subscription. + [Parameter(Mandatory = $false)] + [switch]$All) + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + +<# +.SYNOPSIS + Enable the logging and monitoring for the storage account. +.DESCRIPTION + Initializes an instance of ServiceProperties and then sets the service + properties for all three storage services (blob, table, queue) +.EXAMPLE + EnableMeteringtoStorage -Name "storageAccountName" +#> +function EnableMeteringtoStorage +{ + param( + # Name of storage account + [Parameter(Mandatory = $true)] + [String] + $Name, + + # Name of storage account + [Parameter(Mandatory = $true)] + [Bool] + $SetDefault) + + # Initialize ServiceProperties Instance + + # Configure the Logging parameters + $sp = New-Object -TypeName Microsoft.WindowsAzure.Storage.Shared.Protocol.ServiceProperties + if ($SetDefault) + { + Write-Verbose ("Disabling logging and metrics for storage account {0}" -f $Name ) + $sp.Logging.Version = "1.0"; + $sp.Logging.RetentionDays = $null; + $sp.Logging.LoggingOperations = [Microsoft.WindowsAzure.Storage.Shared.Protocol.LoggingOperations]::None; + + # Configure the metrics parameters + $sp.Metrics.Version = "1.0"; + $sp.Metrics.RetentionDays = $null; + $sp.Metrics.MetricsLevel = [Microsoft.WindowsAzure.Storage.Shared.Protocol.MetricsLevel]::None; + } + else + { + Write-Verbose ("Enabling logging and metrics for storage account {0}" -f $Name ) + $sp.Logging.Version = "1.0"; + $sp.Logging.RetentionDays = 7; + $sp.Logging.LoggingOperations = [Microsoft.WindowsAzure.Storage.Shared.Protocol.LoggingOperations]::All; + + # Configure the metrics parameters + $sp.Metrics.Version = "1.0"; + $sp.Metrics.RetentionDays = 7; + $sp.Metrics.MetricsLevel = [Microsoft.WindowsAzure.Storage.Shared.Protocol.MetricsLevel]::ServiceAndApi; + } + + # Create a storage context for the account. + $keys = Get-AzureStorageKey -StorageAccountName $Name + $context = New-AzureStorageContext -StorageAccountName $Name -StorageAccountKey $keys.Primary + + #Set the service properties for the blob service. + $blobClient = $context.StorageAccount.CreateCloudBlobClient(); + $blobClient.SetServiceProperties($sp); + + #Set the service properties for the table service. + $tableClient = $context.StorageAccount.CreateCloudTableClient(); + $tableClient.SetServiceProperties($sp); + + #Set the service properties for the table service. + $queueClient = $context.StorageAccount.CreateCloudQueueClient(); + $queueClient.SetServiceProperties($sp); +} + +# Validate that either Enable or Disable was specified. +if (!($Enable.IsPresent) -and !($Disable.IsPresent)) +{ + throw "You must specify either the Enable or Disable switch." +} + +$accounts = $null + +if ($All.IsPresent) +{ + #Get all the storage accounts for the default suscription + $accounts = Get-AzureStorageAccount +} +elseif ($StorageAccountName -ne $null) +{ + # Get a specific storage account by name. + $accounts = Get-AzureStorageAccount | Where-Object {$_.StorageAccountName -eq $StorageAccountName } +} + +# Enable logging and metrics for storage account(s). +if ($accounts -ne $null) +{ + foreach($StorageAccount in $accounts) + { + EnableMeteringtoStorage -Name $StorageAccount.StorageAccountName -SetDefault $Disable.IsPresent + } +} +else +{ + Write-Warning "No storage account found. Specify a storage account by name or include the -All switch." +} diff --git a/solutions/data-management/_CopyFilesToAzureStorageContainer.md b/solutions/data-management/_CopyFilesToAzureStorageContainer.md new file mode 100644 index 0000000..33c5891 --- /dev/null +++ b/solutions/data-management/_CopyFilesToAzureStorageContainer.md @@ -0,0 +1,18 @@ +# CopyFilesToAzureStorageContainer # +## Description ## +Copies files (in parallel) from a local folder to a named Azure storage blob container. The copy operation can optionally recurse the local folder using the -Recurse switch. The storage container is assumed to already exist unless the -CreateContainer switch is provided. + + +**Note:** This script requires an Azure Storage Account to run. The storage account can be specified by setting the subscription configuration. For example, + + Set-AzureSubscription -SubscriptionName "MySubscription" -CurrentStorageAccount "MyStorageAccount" + +## Scenario ## +You want to efficiently copy files from a local folder to an Azure storage container. + +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## +- Set-AzureSubscription diff --git a/solutions/data-management/_Remove-BlobsFromAllContainers.md b/solutions/data-management/_Remove-BlobsFromAllContainers.md new file mode 100644 index 0000000..51a0cc3 --- /dev/null +++ b/solutions/data-management/_Remove-BlobsFromAllContainers.md @@ -0,0 +1,19 @@ +# Remove-BlobsFromAllContainers # +## Description ## +Removes blobs from blob storage containers. The script will enumerate through all containers and remove the blobs, maintaining the existence of the container. If you want to remove the containers, then you can include the RemoveContainer switch. This will be faster than removing the individual blobs in the container but will require you to recreate the container if you wish to use it again. + +Prior to removing all blobs in a container or the container itself, the user is prompted to confirm the operation. This enables you to apply the operation to some (but not all) containers. If you include the Force switch, then all blobs will be removed from all containers and all containers will be removed if the RemoveContainer switch is applied. + +**Note:** This script requires an Azure Storage Account to run. The storage account can be specified by setting the subscription configuration. For example, + + Set-AzureSubscription -SubscriptionName "MySubscription" -CurrentStorageAccount "MyStorageAccount" + +## Scenario ## +You want to remove all blobs from a container or set of containers. Or, you want to remove containers and the blobs within the container. + +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## +- Set-AzureSubscription \ No newline at end of file diff --git a/solutions/data-management/_Set-StorageServiceProperties.md b/solutions/data-management/_Set-StorageServiceProperties.md new file mode 100644 index 0000000..52adc5d --- /dev/null +++ b/solutions/data-management/_Set-StorageServiceProperties.md @@ -0,0 +1,17 @@ +# Set-StorageServiceProperties # +## Description ## +Sets storage logging and metrics settings on storage accounts in the current subscription. Settings can be enable or disabled. + +**Note:** This script requires an Azure Storage Account to run. The storage account can be specified by setting the subscription configuration. For example, + + Set-AzureSubscription -SubscriptionName "MySubscription" -CurrentStorageAccount "MyStorageAccount" + +## Scenario ## +You want to enable or disable logging and/or metrics on one or more storage accounts in a subscription. + +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## +- Set-AzureSubscription \ No newline at end of file diff --git a/solutions/data-management/place-holder.txt b/solutions/data-management/place-holder.txt deleted file mode 100644 index e69de29..0000000 diff --git a/solutions/infrastructure/Add-AzureStripedDiskSqlVm.ps1 b/solutions/infrastructure/Add-AzureStripedDiskSqlVm.ps1 new file mode 100644 index 0000000..38c1f09 --- /dev/null +++ b/solutions/infrastructure/Add-AzureStripedDiskSqlVm.ps1 @@ -0,0 +1,356 @@ +<# +.SYNOPSIS + Creates a SQL Server VM with striped disks. +.DESCRIPTION + Adds a VM to the active subscription, based on SQL Server 2012 on Windows Server 2012 gallery image. + Adds four disks to the VM and stripe them into two pools. Formats them for use, creates a database, + putting the data files on one volume and the log files on the other. + Demonstrates the use of PowerShell scripts to create VMs and Disks, but further demonstrates the + use of Remote PowerShell Scripting - running a script on your desktop that automates a Windows Azure + VM's environment. +.EXAMPLE + .\Add-AzureStripedDiskSqlVm.ps1 -ServiceName mytestservice ` + -Location "West US" -ComputerName backend -InstanceSize Medium +#> +param +( + + # Name of the service the VMs will be deployed to. If the service exists, the + # VMs will be deployed ot this service, otherwise, it will be created. + [Parameter(Mandatory = $true)] + [String] + $ServiceName, + + # The target region the VMs will be deployed to. This is used to create the + # affinity group if it does not exist. If the affinity group exists, but in + # a different region, the commandlet displays a warning. + [Parameter(Mandatory = $true)] + [String] + $Location, + + # The computer name for the SQL server. + [Parameter(Mandatory = $true)] + [String] + $ComputerName, + + # Instance size for the SQL server. We will use 4 disks, so it has to be a + # minimum Medium size. The validate set checks that. + [Parameter(Mandatory = $true)] + [ValidateSet("Medium", "Large", "ExtraLarge", "A6", "A7")] + [String] + $InstanceSize) + + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + + +<# +.SYNOPSIS + Installs a Windows Remote Management (WinRm) certificate to the local store +.DESCRIPTION + Gets the WinRM certificate from the Virtual Machine in the Service Name specified, and + installs it on the Current User's personal store. +.EXAMPLE + Install-WinRmCertificate -ServiceName testservice -vmName testVm +.INPUTS + None +.OUTPUTS + None +#> +function Install-WinRmCertificate($ServiceName, $VMName) +{ + $vm = Get-AzureVM -ServiceName $ServiceName -Name $VMName + $winRmCertificateThumbprint = $vm.VM.DefaultWinRMCertificateThumbprint + + $winRmCertificate = Get-AzureCertificate -ServiceName $ServiceName -Thumbprint $winRmCertificateThumbprint -ThumbprintAlgorithm sha1 + + $installedCert = Get-Item Cert:\CurrentUser\My\$winRmCertificateThumbprint -ErrorAction SilentlyContinue + + if ($installedCert -eq $null) + { + $certBytes = [System.Convert]::FromBase64String($winRmCertificate.Data) + $x509Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate + $x509Cert.Import($certBytes) + + $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root", "LocalMachine" + $store.Open("ReadWrite") + $store.Add($x509Cert) + $store.Close() + } +} + + +<# +.SYNOPSIS + Returns the latest image for a given image family name filter. +.DESCRIPTION + Will return the latest image based on a filter match on the ImageFamilyName and + PublisedDate of the image. The more specific the filter, the more control you have + over the object returned. +.EXAMPLE + The following example will return the latest SQL Server image. It could be SQL Server + 2014, 2012 or 2008 + + Get-LatestImage -ImageFamilyNameFilter "*SQL Server*" + + + The following example will return the latest SQL Server 2014 image. This function will + also only select the image from images published by Microsoft. + + Get-LatestImage -ImageFamilyNameFilter "*SQL Server 2014*" -OnlyMicrosoftImages + + + The following example will return $null because Microsoft doesn't publish Ubuntu images. + + Get-LatestImage -ImageFamilyNameFilter "*Ubuntu*" -OnlyMicrosoftImages +#> + + +function Get-LatestImage +{ + param + ( + # A filter for selecting the image family. + # For example, "Windows Server 2012*", "*2012 Datacenter*", "*SQL*, "Sharepoint*" + [Parameter(Mandatory = $true)] + [String] + $ImageFamilyNameFilter, + + + # A switch to indicate whether or not to select the latest image where the publisher is Microsoft. + # If this switch is not specified, then images from all possible publishers are considered. + [Parameter(Mandatory = $false)] + [switch] + $OnlyMicrosoftImages + ) + + + # Get a list of all available images. + $imageList = Get-AzureVMImage + + + if ($OnlyMicrosoftImages.IsPresent) + { + $imageList = $imageList | + Where-Object { ` + ($_.PublisherName -ilike "Microsoft*" -and ` + $_.ImageFamily -ilike $ImageFamilyNameFilter ) } + } + else + { + $imageList = $imageList | + Where-Object { ` + ($_.ImageFamily -ilike $ImageFamilyNameFilter ) } + } + + + $imageList = $imageList | + Sort-Object -Unique -Descending -Property ImageFamily | + Sort-Object -Descending -Property PublishedDate + + + $imageList | Select-Object -First(1) +} + +# Check if the current subscription's storage account's location is the same as the Location parameter +$subscription = Get-AzureSubscription -Current +$currentStorageAccountLocation = (Get-AzureStorageAccount -StorageAccountName $subscription.CurrentStorageAccount).GeoPrimaryLocation + +if ($Location -ne $currentStorageAccountLocation) +{ + throw "Selected location parameter value, ""$Location"" is not the same as the active (current) subscription's current storage account location ` + ($currentStorageAccountLocation). Either change the location parameter value, or select a different storage account for the ` + subscription." +} +$existingVm = Get-AzureVM -ServiceName $ServiceName -Name $ComputerName -ErrorAction SilentlyContinue +if ($existingVm -ne $null) +{ + throw "A VM with name $ComputerName exists on $ServiceName" +} + +# Get an image to provision virtual machines from. +$imageFamilyNameFilter = "SQL Server 2012 SP1 Standard on WS 2012" +$image = Get-LatestImage -ImageFamilyNameFilter $imageFamilyNameFilter -OnlyMicrosoftImages +if ($image -eq $null) +{ + throw "Unable to find an image for $imageFamilyNameFilter to provision Virtual Machine." +} + + +Write-Verbose "Prompt user for administrator credentials to use when provisioning the virtual machine(s)." +$credential = Get-Credential +Write-Verbose "Administrator credentials captured. Use these credentials to login to the virtual machine(s) when the script is complete." + + +$vm = New-AzureVMConfig -Name $ComputerName -InstanceSize $InstanceSize ` + -ImageName $image.ImageName | + Add-AzureProvisioningConfig -Windows -AdminUsername $credential.GetNetworkCredential().username ` + -Password $credential.GetNetworkCredential().password + + +# This example assumes the use of Medium instance size, thus hardcoding the number disks to add. +# Please see http://msdn.microsoft.com/en-us/library/windowsazure/dn197896.aspx for Azure instance sizes +$numberOfDisks = 4 +$numberOfDisksPerPool = 2 +$numberOfPools = 2 + + +# we will be striping the disks, with one copy. To illustrate this point, let's check if the disks add up. +if ($numberOfDisks -ne ($numberOfPools * $numberOfDisksPerPool)) +{ + throw "The total number of disks requested in the pools cannot be different than the available disks" +} + + +for ($index = 0; $index -lt $numberOfDisks; $index++) +{ + $label = "Data disk " + $index + $vm = $vm | Add-AzureDataDisk -CreateNew -DiskSizeInGB 10 -DiskLabel $label -LUN $index +} + + +if (Test-AzureName -Service -Name $ServiceName) +{ + New-AzureVM -ServiceName $ServiceName -VMs $vm -WaitForBoot | Out-Null + if ($?) + { + Write-Verbose "Created the VMs." + } +} +else +{ + New-AzureVM -ServiceName $ServiceName -Location $Location -VMs $vm -WaitForBoot | Out-Null + if ($?) + { + Write-Verbose "Created the VMs and the cloud service $ServiceName" + } +} + + +# Get the RemotePS/WinRM Uri to connect to +$winRmUri = Get-AzureWinRMUri -ServiceName $ServiceName -Name $ComputerName + + +Install-WinRmCertificate $ServiceName $ComputerName + + +# following is a generic script that stripes n disk groups of m +$setDiskStripingScript = +{ + param ([Int] $numberOfPools, [Int] $numberOfDisksPerPool) + + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned + + $uninitializedDisks = Get-PhysicalDisk -CanPool $true + + $virtualDiskJobs = @() + + for ($index = 0; $index -lt $numberOfPools; $index++) + { + $poolDisks = $uninitializedDisks | Select-Object -Skip ($index * $numberOfDisksPerPool) -First $numberOfDisksPerPool + + $poolName = "Pool" + $index + $newPool = New-StoragePool -FriendlyName $poolName -StorageSubSystemFriendlyName "Storage Spaces*" -PhysicalDisks $poolDisks + + $virtualDiskJobs += New-VirtualDisk -StoragePoolFriendlyName $poolName -FriendlyName $poolName -ResiliencySettingName Simple -ProvisioningType Fixed -Interleave 1048576 ` + -NumberOfDataCopies 1 -NumberOfColumns $numberOfDisksPerPool -UseMaximumSize -AsJob + } + + Receive-Job -Job $virtualDiskJobs -Wait + Wait-Job -Job $virtualDiskJobs + Remove-Job -Job $virtualDiskJobs + + # Initialize and format the virtual disks on the pools + $formatted = Get-VirtualDisk | Initialize-Disk -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -FileSystem NTFS -Confirm:$false + + # Create the data directory + $formatted | ForEach-Object { + # Get current drive letter. + $downloadDriveLetter = $_.DriveLetter + + # Create the data directory + $dataDirectory = "$($downloadDriveLetter):\Data" + + New-Item $dataDirectory -Type directory -Force | Out-Null + } + + # Dive time to the storage service to pick up the changes + Start-Sleep -Seconds 120 + + Import-Module “sqlps” -DisableNameChecking + + $createDatabaseScript = " + USE master + GO + CREATE DATABASE TestData + ON + PRIMARY (NAME = Testdata1, + FILENAME = '$($formatted[0].DriveLetter):\Data\testdata1.mdf', + SIZE = 100MB, + MAXSIZE = 200, + FILEGROWTH = 20)" + + # Now add the other drives + $remainingDrives = $formatted | Select-Object -Skip 1 + $index = 2 + foreach ($drive in $remainingDrives) + { + $createDatabaseScript += "," + $dataFileName = "Testdata" + $index + $createDatabaseScript += " + (NAME = $dataFileName, + FILENAME = '$($drive.DriveLetter):\Data\$dataFileName.ndf', + SIZE = 100MB, + MAXSIZE = 200, + FILEGROWTH = 20)" + $index++ + } + + # And create the logs + $createDatabaseScript += " + LOG ON (NAME = Testdatalog1, + FILENAME = '$($formatted[0].DriveLetter):\Data\Testdatalog1.ldf', + SIZE = 100MB, + MAXSIZE = 200, + FILEGROWTH = 20)" + $index = 2 + foreach ($drive in $remainingDrives) + { + $createDatabaseScript += "," + $dataFileName = "Testdatalog" + $index + $createDatabaseScript += " + (NAME = $dataFileName, + FILENAME = '$($drive.DriveLetter):\Data\$dataFileName.ldf', + SIZE = 100MB, + MAXSIZE = 200, + FILEGROWTH = 20)" + $index++ + } + + # Create the batch for the create database statement + $createDatabaseScript += " + GO" + Invoke-Sqlcmd -Query $createDatabaseScript + + # Create the firewall rule for the SQL Server access + netsh advfirewall firewall add rule name= "SQLServer" dir=in action=allow protocol=TCP localport=1433 +} + + +# Following is a special condition for striping for this deployment, +# with 2 groups, 2 disks each (thus @(2, 2) parameters)" +Invoke-Command -ConnectionUri $winRmUri.ToString() -Credential $credential ` + -ScriptBlock $setDiskStripingScript -ArgumentList @($numberOfPools, $numberOfDisksPerPool) + diff --git a/solutions/infrastructure/Add-AzureVMToVnet.ps1 b/solutions/infrastructure/Add-AzureVMToVnet.ps1 new file mode 100644 index 0000000..8cc9cb3 Binary files /dev/null and b/solutions/infrastructure/Add-AzureVMToVnet.ps1 differ diff --git a/solutions/infrastructure/Add-AzureWebApp.ps1 b/solutions/infrastructure/Add-AzureWebApp.ps1 new file mode 100644 index 0000000..3510709 Binary files /dev/null and b/solutions/infrastructure/Add-AzureWebApp.ps1 differ diff --git a/solutions/infrastructure/Add-DataDisksToVM.ps1 b/solutions/infrastructure/Add-DataDisksToVM.ps1 new file mode 100644 index 0000000..cdf638c Binary files /dev/null and b/solutions/infrastructure/Add-DataDisksToVM.ps1 differ diff --git a/solutions/infrastructure/BlogengineNet.app b/solutions/infrastructure/BlogengineNet.app new file mode 100644 index 0000000..fce53cd --- /dev/null +++ b/solutions/infrastructure/BlogengineNet.app @@ -0,0 +1 @@ +Application Path[@]Default Web Site/blogengine diff --git a/solutions/infrastructure/New-AzureMongoDbApp.ps1 b/solutions/infrastructure/New-AzureMongoDbApp.ps1 new file mode 100644 index 0000000..ce50c71 Binary files /dev/null and b/solutions/infrastructure/New-AzureMongoDbApp.ps1 differ diff --git a/solutions/infrastructure/New-AzureRedundantVm.ps1 b/solutions/infrastructure/New-AzureRedundantVm.ps1 new file mode 100644 index 0000000..71bfdbc Binary files /dev/null and b/solutions/infrastructure/New-AzureRedundantVm.ps1 differ diff --git a/solutions/infrastructure/New-AzureVmImageWithWebPiApp.ps1 b/solutions/infrastructure/New-AzureVmImageWithWebPiApp.ps1 new file mode 100644 index 0000000..37406c1 --- /dev/null +++ b/solutions/infrastructure/New-AzureVmImageWithWebPiApp.ps1 @@ -0,0 +1,415 @@ +<# +.SYNOPSIS + Create a new VM Image, based on the provided stock image, and the WebPI application. +.DESCRIPTION + Creates a new VM image, based on the provided stock image name. The stock image name + can be retrieved from the ImageName property of the Images returned by Get-AzureVMImage cmdlet. + The cmdlet also installs the provided WebPi component, and creates a new image for future + use, which is added to the subscription's library. +.EXAMPLE + New-AzureVmImageWithWebPiApp.ps1 ` + -WebPIApplicationName blogengineNET -WebPIApplicationAnswerFile .\BlogengineNet.app ` + -ImageName bengineimage -ImageLabel bengineimagelabel +.OUTPUTS + Microsoft.WindowsAzure.Management.ServiceManagement.Model.OSImageContext +#> + + +param +( + # The WebPI application ID (Currently supports WebPI applications only). + [Parameter(Mandatory = $true)] + [String] + $WebPIApplicationName, + + # The WebPI application answer file full path. + [Parameter(Mandatory = $true)] + [String] + $WebPIApplicationAnswerFile, + + # Name of the new image. + [Parameter(Mandatory = $true)] + [String] + $ImageName, + + # Label of the new image. + [Parameter(Mandatory = $true)] + [String] + $ImageLabel) + + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please make sure to install them from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + + +<# +.SYNOPSIS + Returns the latest image for a given image family name filter. +.DESCRIPTION + Will return the latest image based on a filter match on the ImageFamilyName and + PublisedDate of the image. The more specific the filter, the more control you have + over the object returned. +.EXAMPLE + The following example will return the latest SQL Server image. It could be SQL Server + 2014, 2012 or 2008 + + Get-LatestImage -ImageFamilyNameFilter "*SQL Server*" + + + The following example will return the latest SQL Server 2014 image. This function will + also only select the image from images published by Microsoft. + + Get-LatestImage -ImageFamilyNameFilter "*SQL Server 2014*" -OnlyMicrosoftImages + + + The following example will return $null because Microsoft doesn't publish Ubuntu images. + + Get-LatestImage -ImageFamilyNameFilter "*Ubuntu*" -OnlyMicrosoftImages +#> +function Get-LatestImage +{ + param + ( + # A filter for selecting the image family. + # For example, "Windows Server 2012*", "*2012 Datacenter*", "*SQL*, "Sharepoint*" + [Parameter(Mandatory = $true)] + [String] + $ImageFamilyNameFilter, + + + # A switch to indicate whether or not to select the latest image where the publisher is Microsoft. + # If this switch is not specified, then images from all possible publishers are considered. + [Parameter(Mandatory = $false)] + [switch] + $OnlyMicrosoftImages + ) + + + # Get a list of all available images. + $imageList = Get-AzureVMImage + + + if ($OnlyMicrosoftImages.IsPresent) + { + $imageList = $imageList | + Where-Object { ` + ($_.PublisherName -ilike "Microsoft*" -and ` + $_.ImageFamily -ilike $ImageFamilyNameFilter ) } + } + else + { + $imageList = $imageList | + Where-Object { ` + ($_.ImageFamily -ilike $ImageFamilyNameFilter ) } + } + + + $imageList = $imageList | + Sort-Object -Unique -Descending -Property ImageFamily | + Sort-Object -Descending -Property PublishedDate + + + $imageList | Select-Object -First(1) +} + + +# Get an image to provision virtual machines from. +$imageFamilyNameFilter = "Windows Server 2012 Datacenter" +$image = Get-LatestImage -ImageFamilyNameFilter $imageFamilyNameFilter -OnlyMicrosoftImages +if ($image -eq $null) +{ + throw "Unable to find an image for $imageFamilyNameFilter to provision Virtual Machine." +} + + +<# +.SYNOPSIS + Installs a WinRm certificate to the local store +.DESCRIPTION + Gets the WinRM certificate from the Virtual Machine in the Service Name specified, and + installs it on the Current User's personal store. +.EXAMPLE + Install-WinRmCertificate -ServiceName testservice -vmName testVm +.INPUTS + None +.OUTPUTS + None +#> +function Install-WinRmCertificate($ServiceName, $VMName) +{ + $vm = Get-AzureVM -ServiceName $ServiceName -Name $VMName + $winRmCertificateThumbprint = $vm.VM.DefaultWinRMCertificateThumbprint + + $winRmCertificate = Get-AzureCertificate -ServiceName $ServiceName -Thumbprint $winRmCertificateThumbprint -ThumbprintAlgorithm sha1 + + $installedCert = Get-Item Cert:\CurrentUser\My\$winRmCertificateThumbprint -ErrorAction SilentlyContinue + + if ($installedCert -eq $null) + { + $certBytes = [System.Convert]::FromBase64String($winRmCertificate.Data) + $x509Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate + $x509Cert.Import($certBytes) + + $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root", "LocalMachine" + $store.Open("ReadWrite") + $store.Add($x509Cert) + $store.Close() + } +} + + +<# +.SYNOPSIS + Sends a file to a remote session. +.EXAMPLE + $remoteSession = New-PSSession -ConnectionUri $remoteWinRmUri.AbsoluteUri -Credential $credential + Send-File -Source "c:\temp\myappdata.xml" -Destination "c:\temp\myappdata.xml" $remoteSession +#> +function Send-File +{ + param ( + + # The path on the local computer + [Parameter(Mandatory = $true)] + $Source, + + # The target path on the remote computer + [Parameter(Mandatory = $true)] + $Destination, + + # The session that represents the remote computer + [Parameter(Mandatory = $true)] + [System.Management.Automation.Runspaces.PSSession] $Session) + + $remoteScript = + { + param ($destination, $bytes) + + # Convert the destination path to a full filesystem path (to support relative paths) + $destination = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($destination) + + # Write the content to the new file + $file = [IO.File]::Open($destination, "OpenOrCreate") + $null = $file.Seek(0, "End") + $null = $file.Write($bytes, 0, $bytes.Length) + $file.Close() + } + + # Get the source file, and then start reading its content + $sourceFile = Get-Item $Source + + # Delete the previously-existing file if it exists + Invoke-Command -Session $Session { + if (Test-Path $args[0]) + { + Remove-Item $args[0] + } + + $destinationDirectory = Split-Path -LiteralPath $args[0] + if (!(Test-Path $destinationDirectory)) + { + New-Item -ItemType Directory -Force -Path $destinationDirectory | Out-Null + } + } -ArgumentList $Destination + + # Now break it into chunks to stream + Write-Progress -Activity "Sending $Source" -Status "Preparing file" + $streamSize = 1MB + $position = 0 + $rawBytes = New-Object byte[] $streamSize + $file = [IO.File]::OpenRead($sourceFile.FullName) + while (($read = $file.Read($rawBytes, 0, $streamSize)) -gt 0) + { + Write-Progress -Activity "Writing $Destination" ` + -Status "Sending file" ` + -PercentComplete ($position / $sourceFile.Length * 100) + + # Ensure that our array is the same size as what we read + + # from disk + if ($read -ne $rawBytes.Length) + { + [Array]::Resize( [ref] $rawBytes, $read) + } + + # And send that array to the remote system + Invoke-Command -Session $session $remoteScript ` + -ArgumentList $destination, $rawBytes + + # Ensure that our array is the same size as what we read + + # from disk + if ($rawBytes.Length -ne $streamSize) + { + [Array]::Resize( [ref] $rawBytes, $streamSize) + } + [GC]::Collect() + $position += $read + } + + $file.Close() + + # Show the result + Invoke-Command -Session $Session { Get-Item $args[0] } -ArgumentList $Destination +} + + +# Create a random temporary subdomain name to deploy the VM to. +$serviceName = [System.Guid]::NewGuid() +$hostName = "temphost" +Write-Verbose "Prompt user for admininstrator credentials to use when provisioning the virtual machine(s)." +$credential = Get-Credential +Write-Verbose "Administrator credentials captured. Use these credentials to login to the virtual machine(s) when the script is complete." + +# Determine the target location from the current storage account on the subscription. +$subscription = Get-AzureSubscription -Current +$currentStorageAccountName = $subscription.CurrentStorageAccount +if ($currentStorageAccountName -eq "") +{ + throw "Please set the current storage account on the default subscription with Set-AzureSubscription -SubscriptionName ` + -CurrentStorageAccount " +} + +$currentStorageAccount = Get-AzureStorageAccount -StorageAccountName $currentStorageAccountName +Write-Progress -Activity "Creating VM Image" -Status "Received storage account details" -PercentComplete 1 +$targetLocation = $currentStorageAccount.Location + + +# Deploy the VM +$existingVm = Get-AzureVM -ServiceName $serviceName -Name $HostName -ErrorAction SilentlyContinue +Write-Progress -Activity "Creating VM Image" -Status "Checked an existing VM" -PercentComplete 2 +if ($existingVm -ne $null) +{ + throw "A VM with name $HostName exists on $serviceName" +} + + +Write-Progress -Activity "Creating VM Image" -Status "Creating the temporary VM." -PercentComplete 3 + + +$vms = @() + + +$vms += New-AzureVMConfig -Name $hostName -InstanceSize Small -ImageName $image.ImageName | + Add-AzureProvisioningConfig -Windows -AdminUsername $credential.GetNetworkCredential().username ` + -Password $credential.GetNetworkCredential().password + + +New-AzureVM -ServiceName $serviceName -Location $targetLocation -VMs $vms -WaitForBoot | Out-Null + + +Write-Progress -Activity "Creating VM Image" -Status "Created the temporary VM deployment" -PercentComplete 50 + + +if ($?) +{ + Write-Verbose "Created the VMs and the cloud service $serviceName" +} + + +# prepare to run the remote execution + + +# Get the RemotePS/WinRM Uri to connect to +$winRmUri = Get-AzureWinRMUri -ServiceName $serviceName -Name $hostName + + +Install-WinRmCertificate $serviceName $hostName +Write-Progress -Activity "Creating VM Image" ` + -Status "Configured WinRM access. Now will start copying the script and answer files to the VM." ` + -PercentComplete 55 + + +$remoteScriptsDirectory = "c:\Scripts" +$remoteScriptFileName = "RemoteScripts.ps1" + + +# Copy the required files to the remote server +$remoteSession = New-PSSession -ConnectionUri $winRmUri.AbsoluteUri -Credential $credential +$sourcePath = "$PSScriptRoot\$remoteScriptFileName" +$remoteScriptFilePath = "$remoteScriptsDirectory\$remoteScriptFileName" +Send-File $sourcePath $remoteScriptFilePath $remoteSession + + +$answerFileName = Split-Path -Leaf $WebPIApplicationAnswerFile +$answerFilePath = "$remoteScriptsDirectory\$answerFileName" +Send-File $WebPIApplicationAnswerFile $answerFilePath $remoteSession +Remove-PSSession -InstanceId $remoteSession.InstanceId + + +Write-Progress -Activity "Creating VM Image" -Status "Copied the files to VM. Now will start runnign the remote script." -PercentComplete 65 + + +# Run the install script for the WebPI application +$runInstallScript = +{ + param ([String]$WebPiApplication, [String]$scriptFilePath, [String] $AnswerFilePath) + + # Usual recommendation is not to set the execution policy to a potentially less restrictive setting then what + + # may have been already set, such as AllSigned. However, in this sample, we know we are creating this VM from + + # scratch and we know the initial setting. + Set-ExecutionPolicy -ExecutionPolicy RemoteSigned + + # Install .NET 3.5 seperately, as it fails through WebPI dependencies install + Import-Module ServerManager + Add-Windowsfeature -Name NET-Framework-Features | Out-Null + Add-Windowsfeature -Name Web-Asp-Net45 | Out-Null + + . $scriptFilePath + + Install-WebPiApplication -ApplicationId $WebPiApplication -AnswerFile $AnswerFilePath + + # Run sysprep to generalize the VM + $sysprepCmd = "$env:windir\System32\Sysprep\sysprep.exe" + $sysprepArgs = "/quiet /generalize /oobe /shutdown" + Start-Process -FilePath $sysprepCmd -ArgumentList $sysprepArgs -PassThru | Wait-Process +} +$argumentList = @( + $WebPIApplicationName, + $remoteScriptFilePath, + $answerFilePath) + + +Invoke-Command -ConnectionUri $winRmUri.ToString() -Credential $credential ` + -ScriptBlock $runInstallScript -ArgumentList $argumentList + + +Write-Progress -Activity "Creating VM Image" -Status "Install WebPI component complete" -PercentComplete 95 + + +$pollTimeout = 15 +do +{ + Write-Verbose "Waiting for $pollTimeout seconds before checking the VM status." + Start-Sleep -Seconds $pollTimeout + $vm = Get-AzureVM -ServiceName $serviceName -Name $hostName +} +until ($vm.PowerState -eq "Stopped") + + +Save-AzureVMImage -ServiceName $serviceName -Name $hostName ` + -NewImageName $ImageName -NewImageLabel $ImageLabel | Out-Null +Write-Progress -Activity "Creating VM Image" -Status "Operation complete" -PercentComplete 100 -Completed + + +# Cleanup +Remove-AzureService -ServiceName $serviceName -Force | Out-Null + + +Get-AzureVMImage -ImageName $ImageName + + + diff --git a/solutions/infrastructure/RemoteScripts.ps1 b/solutions/infrastructure/RemoteScripts.ps1 new file mode 100644 index 0000000..9e32f0d Binary files /dev/null and b/solutions/infrastructure/RemoteScripts.ps1 differ diff --git a/solutions/infrastructure/Start-AzureVMsOnSchedule.ps1 b/solutions/infrastructure/Start-AzureVMsOnSchedule.ps1 new file mode 100644 index 0000000..30e710f --- /dev/null +++ b/solutions/infrastructure/Start-AzureVMsOnSchedule.ps1 @@ -0,0 +1,63 @@ +<# +.SYNOPSIS + Creates scheduled tasks to start Virtual Machines. +.DESCRIPTION + Creates scheduled tasks to start a single Virtual Machine or a set of Virtual Machines (using + wildcard pattern syntax for the Virtual Machine name). +.EXAMPLE + Start-AzureVMsOnSchedule.ps1 -ServiceName "MyServiceName" -VMName "testmachine1" ` + -TaskName "Start Test Machine 1" -At 8AM + + Start-AzureVMsOnSchedule.ps1 -ServiceName "MyServiceName" -VMName "test*" ` + -TaskName "Start All Test Machines" -At 8:15AM +#> + + +param( + # The name of the VM(s) to start on schedule. Can be wildcard pattern. + [Parameter(Mandatory = $true)] + [string]$VMName, + + + # The service name that $VMName belongs to. + [Parameter(Mandatory = $true)] + [string]$ServiceName, + + + # The name of the scheduled task. + [Parameter(Mandatory = $true)] + [string]$TaskName, + + + # The name of the "Stop" scheduled tasks. + [Parameter(Mandatory = $true)] + [DateTime]$At) + + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + + +# Define a scheduled task to start the VM(s) on a schedule. +$startAzureVM = "Start-AzureVM -Name " + $VMName + " -ServiceName " + $ServiceName + " -Verbose" +$startTaskTrigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday,Tuesday,Wednesday,Thursday,Friday -At $At +$startTaskAction = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument $startAzureVM +$startTaskSettingsSet = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries + +$startScheduledTask = New-ScheduledTask -Action $startTaskAction -Trigger $startTaskTrigger -Settings $startTaskSettingsSet + + +# Register the scheduled tasks to start and stop the VM(s). +Register-ScheduledTask -TaskName $TaskName -InputObject $startScheduledTask + diff --git a/solutions/infrastructure/Stop-AzureVMsOnSchedule.ps1 b/solutions/infrastructure/Stop-AzureVMsOnSchedule.ps1 new file mode 100644 index 0000000..d565cf0 --- /dev/null +++ b/solutions/infrastructure/Stop-AzureVMsOnSchedule.ps1 @@ -0,0 +1,61 @@ +<# +.Synopsis + Creates scheduled tasks to stop Virtual Machines. +.DESCRIPTION + Creates scheduled tasks to stop a single Virtual Machine or a set of Virtual Machines (using + wildcard pattern syntax for the Virtual Machine name). +.EXAMPLE + Stop-AzureVMsOnSchedule.ps1 -ServiceName "MyServiceName" -VMName "testmachine1" -TaskName "Stopt Test Machine 1" -At 5:30PM + Stop-AzureVMsOnSchedule.ps1 -ServiceName "MyServiceName" -VMName "test*" -TaskName "Stop All Test Machines" -At 5:30PM +#> + + +param( + # The name of the VM(s) to start on schedule. Can be wildcard pattern. + [Parameter(Mandatory = $true)] + [string]$VMName, + + + # The service name that $VMName belongs to. + [Parameter(Mandatory = $true)] + [string]$ServiceName, + + + # The name of the scheduled task. + [Parameter(Mandatory = $true)] + [string]$TaskName, + + + # The name of the "Stop" scheduled tasks. + [Parameter(Mandatory = $true)] + [DateTime]$At +) + + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + + +# Define a scheduled task to stop the VM(s) on a schedule. +$stopAzureVM = "Stop-AzureVM -Name " + $VMName + " -ServiceName " + $ServiceName + " -StayProvisioned -Force -Verbose > C:\WA-PowerShell\output.txt" +$stopTaskTrigger = New-ScheduledTaskTrigger -Daily -At $At +$stopTaskAction = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument $stopAzureVM +$startTaskSettingsSet = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries + +$stopScheduledTask = New-ScheduledTask -Action $stopTaskAction -Trigger $stopTaskTrigger -Settings $startTaskSettingsSet + + +# Register the scheduled tasks to start and stop the VM(s). +Register-ScheduledTask -TaskName $TaskName -InputObject $stopScheduledTask + diff --git a/solutions/infrastructure/Update-AzureWindowsVm.ps1 b/solutions/infrastructure/Update-AzureWindowsVm.ps1 new file mode 100644 index 0000000..fe055de Binary files /dev/null and b/solutions/infrastructure/Update-AzureWindowsVm.ps1 differ diff --git a/solutions/infrastructure/_Add-AzureWebApp.md b/solutions/infrastructure/_Add-AzureWebApp.md new file mode 100644 index 0000000..402f731 --- /dev/null +++ b/solutions/infrastructure/_Add-AzureWebApp.md @@ -0,0 +1,18 @@ +# Add-AzureWebApp# +## Description ## +Creates two virtual machines; a front-end Windows Server and a back-end SQL server. + +The front-end server is configured with the Web Platform Installer, which is then used to install an application published on the Web Platform Installer catalog. + +The back-end SQL server is configured with "Mixed" mode authentication and a Firewall rule for remote access. + +Both Virtual Machines are placed in a single subnet. +## Scenario ## +You need to create an environment that pre-installs an application from the Web Platfom Installer (for example, Blogengine.net) and connect the Virtual Machine to a new SQL server instance. +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## +- RemoteScripts.ps1 +- BlogengineNet.app \ No newline at end of file diff --git a/solutions/infrastructure/_Add-DataDisksToVM.md b/solutions/infrastructure/_Add-DataDisksToVM.md new file mode 100644 index 0000000..eaf9431 --- /dev/null +++ b/solutions/infrastructure/_Add-DataDisksToVM.md @@ -0,0 +1,16 @@ +# Add-DataDisksToVM# +## Description ## +Creates a Virtual Machine (small) configured with two data disks. After the Virtual Machine is provisioned and running, the data disks are then formatted and drive letters assigned. User is prompted for credentials to use to provision the new Virtual Machine. + +**Note:** This script requires an Azure Storage Account to run. The storage account can be specified by setting the subscription configuration. For example, + + Set-AzureSubscription -SubscriptionName "MySubscription" -CurrentStorageAccount "MyStorageAccount" + +## Scenario ## +You want to provision a Virtual Machine with one or more data disks pre-formatted. +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## +- Set-AzureSubscription diff --git a/solutions/infrastructure/_New-AzureMongoDbApp.md b/solutions/infrastructure/_New-AzureMongoDbApp.md new file mode 100644 index 0000000..6b3fc4b --- /dev/null +++ b/solutions/infrastructure/_New-AzureMongoDbApp.md @@ -0,0 +1,17 @@ +# New-AzureMongoDbApp # +## Description ## +Creates two virtual machines; a front-end Windows Server and a back-end MongoDB server. + +The front-end server is configured with the Web Platform Installer, which is then used to install IIS. + +The back-end MongoDB server is configured with two additional data disk; one for data and another for log files. + +Both Virtual Machines are placed in a single subnet. +## Scenario ## +You need to create an environment with and IIS front-end server and a MongoDB back-end server. +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## +- Get-AzureVMImage \ No newline at end of file diff --git a/solutions/infrastructure/_New-AzureRedundantVm.md b/solutions/infrastructure/_New-AzureRedundantVm.md new file mode 100644 index 0000000..ce20ab5 --- /dev/null +++ b/solutions/infrastructure/_New-AzureRedundantVm.md @@ -0,0 +1,13 @@ +# New-AzureRedundantVm# +## Description ## +Deploy a specified number of Virtual Machines based on a given image name. The Virtual Machines are placed in the same availability set and load balanced on a given endpoint name. + +If the cloud service name already exists, then subsequent call will adds new Virtual Machine instances. +## Scenario ## +You need to create a farm of Virtual Machines using a standard disk image and have all instances load balanced. +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## +- Get-AzureVMImage \ No newline at end of file diff --git a/solutions/infrastructure/_New-AzureVmImageWithWebPiApp.md b/solutions/infrastructure/_New-AzureVmImageWithWebPiApp.md new file mode 100644 index 0000000..4738e7e --- /dev/null +++ b/solutions/infrastructure/_New-AzureVmImageWithWebPiApp.md @@ -0,0 +1,11 @@ +# New-AzureVmImageWithWebPiApp # +## Description ## +Creates a new Virtual Machine image based on a given stock image. Installs an application from the Web Platform Installer. The images is saved to the user's subscription to be used for provisioning future Virtual Machines. +## Scenario ## +You need to create a custom image to use for provisioning new Virtual Machines. +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## +- Get-AzureVMImage \ No newline at end of file diff --git a/solutions/infrastructure/_Start-AzureVMsOnSchedule.md b/solutions/infrastructure/_Start-AzureVMsOnSchedule.md new file mode 100644 index 0000000..6c9fa0f --- /dev/null +++ b/solutions/infrastructure/_Start-AzureVMsOnSchedule.md @@ -0,0 +1,12 @@ +# Start-AzureVMsOnSchedule# +## Description ## +Demonstrates starting a single Virtual Machine or set of Virtual Machines (using a wildcard pattern) within a Cloud Service. It does this by creating scheduled tasks to start the Virtual Machine(s) on a schedule at the time specified. +## Scenario ## +Suppose you have a test machine or set of test machines that you want started every Tue-Thur at 8:00AM. This script will register the scheduled task to start the virtual machines you specify. +## Requirements ## + +- PowerShell Version 0.6.19 +- Windows Azure PowerShell July 2013 + +## See Also ## +- Stop-AzureVMsOnSchedule diff --git a/solutions/infrastructure/_Stop-AzureVMsOnSchedule.md b/solutions/infrastructure/_Stop-AzureVMsOnSchedule.md new file mode 100644 index 0000000..62a6e94 --- /dev/null +++ b/solutions/infrastructure/_Stop-AzureVMsOnSchedule.md @@ -0,0 +1,11 @@ +# Stop-AzureVMsOnSchedule# +## Description ## +Demonstrates stopping a single Virtual Machine or set of Virtual Machines (using a wildcard pattern) within a Cloud Service. It does this by creating scheduled tasks to stop the Virtual Machine(s) on a schedule at the time specified. +## Scenario ## +Suppose you have a test machine or set of test machines that you want turned off everyday at 5:30PM. This script will register the scheduled task to stop the virtual machines you specify. +## Requirements ## +- PowerShell Version 0.6.19 +- Windows Azure PowerShell July 2013 + +## See Also ## +- Start-AzureVMsOnSchedule diff --git a/solutions/infrastructure/place-holder.txt b/solutions/infrastructure/place-holder.txt deleted file mode 100644 index e69de29..0000000 diff --git a/solutions/web/Create-AzureEnterpriseSite.ps1 b/solutions/web/Create-AzureEnterpriseSite.ps1 new file mode 100644 index 0000000..203ca94 --- /dev/null +++ b/solutions/web/Create-AzureEnterpriseSite.ps1 @@ -0,0 +1,437 @@ +<# +.Synopsis + This scripts take a Package (*.cspkg) and config file (*.cscfg) to create a + corporate site on Web Role with Azure SQL application database and Storage + Account. +.DESCRIPTION + This sample script demonstrating how deploy a DotNet corporate site into a + Cloud Services with SQL Database and Storage Acoount. + During de process, it will create Storage Account, Azure Sql Database, + Cloud Services and change de configuration file (*.cscfg) of the project. + + At the end of the script it start the browser and shows the site. The sample + package has a Web site that check the Azure SQL and Storage connection +.EXAMPLE + Use the following to Deploy the project + $test = & ".\Create-AzureEnterpriseSite.ps1" ` + -ServiceName "jpggTest" ` + -ServiceLocation "West US" ` + -sqlAppDatabaseName "myDB" ` + -StartIPAddress "1.0.0.1" ` + -EndIPAddress "255.255.255.255" ` + -ConfigurationFilePath ".\EnterpiseSite\ServiceConfiguration.Cloud.cscfg" ` + -PackageFilePath ".\EnterpiseSite\WebCorpHolaMundo.Azure.cspkg" + +.OUTPUTS + Write in Host the time spended in the script execution +#> +#1. Parameters +Param( + #Cloud services Name + [Parameter(Mandatory = $true)] + [String]$ServiceName, + #Cloud Service location + [Parameter(Mandatory = $true)] + [String]$ServiceLocation, + #Database application name + [Parameter(Mandatory = $true)] + [String]$sqlAppDatabaseName, + #First IP Adress of Ranage of IP's that have access to database. it is use for Firewall rules + [Parameter(Mandatory = $true)] + [String]$StartIPAddress, + #Last IP Adress of Ranage of IP's that have access to database. it is use for Firewall rules + [Parameter(Mandatory = $true)] + [String]$EndIPAddress, + #Path to configuration file (*.cscfg) + [Parameter(Mandatory = $true)] + [String]$ConfigurationFilePath, + #PackageFilePath: Path to Package file (*.cspkg) + [Parameter(Mandatory = $true)] + [String]$PackageFilePath +) +<#2.1 CreateCloudService +.Synopsis +This function create a Cloud Services if this Cloud Service don't exists. + +.DESCRIPTION + This function try to obtain the services using $MyServiceName. If we have + an exception it is mean the Cloud services don’t exist and create it. +.EXAMPLE + CreateCloudService "ServiceName" "ServiceLocation" +#> +Function CreateCloudService +{ + Param( + #Cloud services Name + [Parameter(Mandatory = $true)] + [String]$MyServiceName, + #Cloud service Location + [Parameter(Mandatory = $true)] + [String]$MyServiceLocation + ) + + try + { + $CloudService = Get-AzureService -ServiceName $MyServiceName + Write-Verbose ("cloud service {0} in location {1} exist!" -f $MyServiceName, $MyServiceLocation) + } + catch + { + #Create + Write-Verbose ("[Start] creating cloud service {0} in location {1}" -f $MyServiceName, $MyServiceLocation) + New-AzureService -ServiceName $MyServiceName -Location $MyServiceLocation + Write-Verbose ("[Finish] creating cloud service {0} in location {1}" -f $MyServiceName, $MyServiceLocation) + } +} +<#2.2 CreateStorage +.Synopsis +This function create a Storage Account if it don't exists. + +.DESCRIPTION +This function try to obtain the Storage Account using $MyStorageName. If we have + an exception it is mean the Storage Account don’t exist and create it. + +.OUTPUTS + Storage Account connectionString +.EXAMPLE + CreateStorage -MyStorageAccountName $StorageAccountName -MyStorageLocation $ServiceLocation +#> +Function CreateStorage +{ +Param ( + #Storage Account Name + [Parameter(Mandatory = $true)] + [String]$MyStorageAccountName, + #Storage Account Location + [Parameter(Mandatory = $true)] + [String]$MyStorageLocation +) + try + { + $myStorageAccount= Get-AzureStorageAccount -StorageAccountName $MyStorageAccountName + Write-Verbose ("Storage account {0} in location {1} exist" -f $MyStorageAccountName, $MyStorageLocation) + } + catch + { + # Create a new storage account + Write-Verbose ("[Start] creating storage account {0} in location {1}" -f $MyStorageAccountName, $MyStorageLocation) + New-AzureStorageAccount -StorageAccountName $MyStorageAccountName -Location $MyStorageLocation -Verbose + Write-Verbose ("[Finish] creating storage account {0} in location {1}" -f $MyStorageAccountName, $MyStorageLocation) + } + + # Get the access key of the storage account + $key = Get-AzureStorageKey -StorageAccountName $MyStorageAccountName + + # Generate the connection string of the storage account + $connectionString ="BlobEndpoint=http://{0}.blob.core.windows.net/;" -f $MyStorageAccountName + $connectionString =$connectionString + "QueueEndpoint=http://{0}.queue.core.windows.net/;" -f $MyStorageAccountName + $connectionString =$connectionString + "TableEndpoint=http://{0}.table.core.windows.net/;" -f $MyStorageAccountName + $connectionString =$connectionString + "AccountName={0};AccountKey={1}" -f $MyStorageAccountName, $key.Primary + + Return @{ConnectionString = $connectionString} +} +<#2.3 Update-Cscfg +.Synopsis + This function update Cloud Services configuration file with the Azure SQL and Storage account information +.DESCRIPTION + It load XML file and looking for “dbApplication” and “Storage” XML TAG with the current Azure SQL and Storage account. + It save updated configuration in a temporal file. +.EXAMPLE + Update-Cscfg ` + -MyConfigurationFilePath $ConfigurationFilePath ` + -MySqlConnStr $sql.AppDatabase.ConnectionString ` + -MyStorageConnStr $Storage.ConnectionString +.OUTPUTS + file Path to temp configuration file updated +#> +Function Update-Cscfg +{ +Param ( + #Path to configuration file (*.cscfg) + [Parameter(Mandatory = $true)] + [String]$MyConfigurationFilePath, + #Azure SQL connection string + [Parameter(Mandatory = $true)] + [String]$MySqlConnStr , + #Storage Account connection String + [Parameter(Mandatory = $true)] + [String]$MyStorageConnStr +) + # Get content of the project source cscfg file + [Xml]$cscfgXml = Get-Content $MyConfigurationFilePath + Foreach ($role in $cscfgXml.ServiceConfiguration.Role) + { + Foreach ($setting in $role.ConfigurationSettings.Setting) + { + Switch ($setting.name) + { + "dbApplication" {$setting.value =$MySqlConnStr} #AppDatabase + "Storage" {$setting.value = $MyStorageConnStr} #Storage + } + } + } + #Save the change + $file = "{0}\EnterpiseSite\ServiceConfiguration.Ready.cscfg" -f $ScriptPath + $cscfgXml.InnerXml | Out-File -Encoding utf8 $file + Return $file +} +<# 2.4 DeployPackage +.Synopsis + It deploy service’s package with his configuration to a Cloud Services +.DESCRIPTION + it function try to obtain the Services deployments by name. If exists this deploy is update. In other case, + it create a Deploy and does the upload. +.EXAMPLE + DeployPackage -MyServiceName $ServiceName -MyConfigurationFilePath $NewcscfgFilePath -MyPackageFilePath $PackageFilePath +#> +Function DeployPackage +{ +Param( + #Cloud Services name + [Parameter(Mandatory = $true)] + [String]$MyServiceName, + #Path to configuration file (*.cscfg) + [Parameter(Mandatory = $true)] + [String]$MyConfigurationFilePath, + #Path to package file (*.cspkg) + [Parameter(Mandatory = $true)] + [String]$MyPackageFilePath +) + Try + { + Get-AzureDeployment -ServiceName $MyServiceName + Write-Verbose ("[Start] Deploy Service {0} exist, Will update" -f $MyServiceName) + Set-AzureDeployment ` + -ServiceName $MyServiceName ` + -Slot Production ` + -Configuration $MyConfigurationFilePath ` + -Package $MyPackageFilePath ` + -Mode Simultaneous -Upgrade + Write-Verbose ("[finish] Deploy Service {0} exist, Will update" -f $MyServiceName) + } + Catch + { + Write-Verbose ("[Start] Deploy Service {0} don't exist, Will create" -f $MyServiceName) + New-AzureDeployment -ServiceName $MyServiceName -Slot Production -Configuration $MyConfigurationFilePath -Package $MyPackageFilePath + Write-Verbose ("[Finish] Deploy Service {0} don't exist, Will create" -f $MyServiceName) + } + +} +<#2.5 WaitRoleInstanceReady +.Synopsis + it wait all role instance are ready +.DESCRIPTION + Wait until al instance of Role are ready +.EXAMPLE + WaitRoleInstanceReady $ServiceName +#> +function WaitRoleInstanceReady +{ +Param( + #Cloud Services name + [Parameter(Mandatory = $true)] + [String]$MyServiceName +) + Write-Verbose ("[Start] Waiting for Instance Ready") + do + { + $MyDeploy = Get-AzureDeployment -ServiceName $MyServiceName + foreach ($Instancia in $MyDeploy.RoleInstanceList) + { + $switch=$true + Write-Verbose ("Instance {0} is in state {1}" -f $Instancia.InstanceName, $Instancia.InstanceStatus ) + if ($Instancia.InstanceStatus -ne "ReadyRole") + { + $switch=$false + } + } + if (-Not($switch)) + { + Write-Verbose ("Waiting Azure Deploy running, it status is {0}" -f $MyDeploy.Status) + Start-Sleep -s 10 + } + else + { + Write-Verbose ("[Finish] Waiting for Instance Ready") + } + } + until ($switch) +} + + +<#2.6 Detect-IPAddress +.Synopsis + Get the IP Range needed to be whitelisted for SQL Azure +.OUTPUTS + Client IP Address +#> +Function Detect-IPAddress +{ + $ipregex = "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" + $text = Invoke-RestMethod 'http://www.whatismyip.com/api/wimi.php' + $result = $null + + If($text -match $ipregex) + { + $ipaddress = $matches[0] + $ipparts = $ipaddress.Split('.') + $ipparts[3] = 0 + $startip = [string]::Join('.',$ipparts) + $ipparts[3] = 255 + $endip = [string]::Join('.',$ipparts) + + $result = @{StartIPAddress = $startip; EndIPAddress = $endip} + } + + Return $result +} +<#2.7 Get-SQLAzureDatabaseConnectionString +.Synopsis + 3. Generate connection string of a given SQL Azure database +.EXAMPLE + Get-SQLAzureDatabaseConnectionString -DatabaseServerName $databaseServer.ServerName -DatabaseName $AppDatabaseName -SqlDatabaseUserName $SqlDatabaseUserName -Password $Password +.OUTPUT + Connection String +#> +Function Get-SQLAzureDatabaseConnectionString +{ + Param( + #Database Server Name + [String]$DatabaseServerName, + #Database name + [String]$DatabaseName, + #Database User Name + [String]$SqlDatabaseUserName , + #Database User Password + [String]$Password + ) + + Return "Server=tcp:{0}.database.windows.net,1433;Database={1};User ID={2}@{0};Password={3};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;" -f + $DatabaseServerName, $DatabaseName, $SqlDatabaseUserName , $Password +} +<#2.8 CreateAzureSqlDB +.Synopsis + This script create Azure SQl Server and Database +.EXAMPLE How to Run this script + .\New-AzureSql.ps1 " -AppDatabaseName "XXXXXX" + -StartIPAddress "XXXXXX"  + -EndIPAddress "XXXXXX" + -Location "XXXXXX + -FirewallRuleName ""XXXX" + +.OUTPUTS + Database connection string in a hastable +#> +Function CreateAzureSqlDB +{ +Param( + #Application database name + [Parameter(Mandatory = $true)] + [String]$AppDatabaseName, + #Database server firewall rule name + [Parameter(Mandatory = $true)] + [String]$FirewallRuleName , + #First IP Adress of Ranage of IP's that have access to database. it is use for Firewall rules + [Parameter(Mandatory = $true)] + [String]$StartIPAddress, + #Last IP Adress of Ranage of IP's that have access to database. it is use for Firewall rules + [Parameter(Mandatory = $true)] + [String]$EndIPAddress, + #Database Server Location + [Parameter(Mandatory = $true)] + [String]$Location +) + +#a. Detect IP range for SQL Azure whitelisting if the IP range is not specified +If (-not ($StartIPAddress -and $EndIPAddress)) +{ + $ipRange = Detect-IPAddress + $StartIPAddress = $ipRange.StartIPAddress + $EndIPAddress = $ipRange.EndIPAddress +} + +#b. Prompt a Credential +$credential = Get-Credential +#c Create Server +Write-Verbose ("[Start] creating SQL Azure database server in location {0} with username {1} and password {2}" -f $Location, $credential.UserName , $credential.GetNetworkCredential().Password) +$databaseServer = New-AzureSqlDatabaseServer -AdministratorLogin $credential.UserName -AdministratorLoginPassword $credential.GetNetworkCredential().Password -Location $Location +Write-Verbose ("[Finish] creating SQL Azure database server {3} in location {0} with username {1} and password {2}" -f $Location, $credential.UserName , $credential.GetNetworkCredential().Password, $databaseServer.ServerName) + +#C. Create a SQL Azure database server firewall rule for the IP address of the machine in which this script will run +# This will also whitelist all the Azure IP so that the website can access the database server +Write-Verbose ("[Start] creating firewall rule {0} in database server {1} for IP addresses {2} - {3}" -f $RuleName, $databaseServer.ServerName, $StartIPAddress, $EndIPAddress) +New-AzureSqlDatabaseServerFirewallRule -ServerName $databaseServer.ServerName -RuleName $FirewallRuleName -StartIpAddress $StartIPAddress -EndIpAddress $EndIPAddress -Verbose +New-AzureSqlDatabaseServerFirewallRule -ServerName $databaseServer.ServerName -RuleName "AllowAllAzureIP" -StartIpAddress "0.0.0.0" -EndIpAddress "0.0.0.0" -Verbose +Write-Verbose ("[Finish] creating firewall rule {0} in database server {1} for IP addresses {2} - {3}" -f $FirewallRuleName, $databaseServer.ServerName, $StartIPAddress, $EndIPAddress) + +#d. Create a database context which includes the server name and credential +$context = New-AzureSqlDatabaseServerContext -ServerName $databaseServer.ServerName -Credential $credential + +# e. Use the database context to create app database +Write-Verbose ("[Start] creating database {0} in database server {1}" -f $AppDatabaseName, $databaseServer.ServerName) +New-AzureSqlDatabase -DatabaseName $AppDatabaseName -Context $context -Verbose +Write-Verbose ("[Finish] creating database {0} in database server {1}" -f $AppDatabaseName, $databaseServer.ServerName) + +#f. Generate the ConnectionString +[string] $appDatabaseConnectionString = Get-SQLAzureDatabaseConnectionString -DatabaseServerName $databaseServer.ServerName -DatabaseName $AppDatabaseName -SqlDatabaseUserName $credential.UserName -Password $credential.GetNetworkCredential().Password + +#g.Return Database connection string + Return @{ConnectionString = $appDatabaseConnectionString;} +} + + + +# 3.0 Same variables tu use in the Script +$VerbosePreference = "Continue" +$ErrorActionPreference = "Stop" +# Get the directory of the current script +$ScriptPath = Split-Path -parent $PSCommandPath +# Mark the start time of the script execution +$StartTime = Get-Date +# Define the names of storage account, SQL Azure database and SQL Azure database server firewall rule +$ServiceName = $ServiceName.ToLower() +$StorageAccountName = "{0}storage" -f $ServiceName +$SqlDatabaseServerFirewallRuleName = "{0}rule" -f $ServiceName + +# 3.1 Create a new cloud service? +#creating Windows Azure cloud service environment +Write-Verbose ("[Start] Validating Windows Azure cloud service environment {0}" -f $ServiceName) +CreateCloudService $ServiceName $ServiceLocation + +#3.2 Create a new storage account +$Storage = CreateStorage -MyStorageAccountName $StorageAccountName -MyStorageLocation $ServiceLocation + +#3.3 Create a SQL Azure database server and Application Database +[string] $SqlConn = CreateAzureSqlDB ` + -AppDatabaseName $sqlAppDatabaseName ` + -StartIPAddress $StartIPAddress ` + -EndIPAddress $EndIPAddress -FirewallRuleName $SqlDatabaseServerFirewallRuleName ` + -Location $ServiceLocation + +Write-Verbose ("[Finish] creating Windows Azure cloud service environment {0}" -f $ServiceName) + +# 3.4 Upgrade configuration File with the SQL and Storage references +$NewcscfgFilePath = Update-Cscfg ` + -MyConfigurationFilePath $ConfigurationFilePath ` + -MySqlConnStr $SqlConn ` + -MyStorageConnStr $Storage.ConnectionString +Write-Verbose ("New Config File {0}" -f $NewcscfgFilePath) + +# 3.5 Deploy Package +DeployPackage -MyServiceName $ServiceName -MyConfigurationFilePath $NewcscfgFilePath -MyPackageFilePath $PackageFilePath + +#3.5.1 Delete temporal configFile +Remove-Item $NewcscfgFilePath + +# 3.6 Wait Role isntances Ready +WaitRoleInstanceReady $ServiceName + + +#4.1 Mark the finish time of the script execution +# Output the time consumed in seconds +$finishTime = Get-Date + +Write-Host ("Total time used (seconds): {0}" -f ($finishTime - $StartTime).TotalSeconds) + +#4.2 Launch the Site +Start-Process -FilePath ("http://{0}.cloudapp.net" -f $ServiceName) diff --git a/solutions/web/EnterpiseSite/ServiceConfiguration.Cloud.cscfg b/solutions/web/EnterpiseSite/ServiceConfiguration.Cloud.cscfg new file mode 100644 index 0000000..99d870c --- /dev/null +++ b/solutions/web/EnterpiseSite/ServiceConfiguration.Cloud.cscfg @@ -0,0 +1,20 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/solutions/web/EnterpiseSite/WebCorpHolaMundo.Azure.cspkg b/solutions/web/EnterpiseSite/WebCorpHolaMundo.Azure.cspkg new file mode 100644 index 0000000..bfa1534 Binary files /dev/null and b/solutions/web/EnterpiseSite/WebCorpHolaMundo.Azure.cspkg differ diff --git a/solutions/web/Get-AzureWebsiteLogAnalysis.ps1 b/solutions/web/Get-AzureWebsiteLogAnalysis.ps1 new file mode 100644 index 0000000..269a1ab --- /dev/null +++ b/solutions/web/Get-AzureWebsiteLogAnalysis.ps1 @@ -0,0 +1,144 @@ +<# +.SYNOPSIS + Downloads IIS logs from an Azure Website and searches log for HTTP 400 and above status codes. +.DESCRIPTION + Downloads IIS logs from the Azure Website. If Htt logging is not enabled on the website, then it will + enable logging if the EnableHttpLogging switch is specified. + + The downloaded logs are unzipped and then fed into LogParser (if installed), querying for any HTTP + status codes of 400 and higher. The output of the LogParser query output to the console. +.EXAMPLE + .\Get-AzureWebsiteLogAnalysis.ps1 -Name "MyWebsite" -OutputDir "c:\users\\desktop\logs" -EnableHttpLogging +#> + +param( + # Website name from which logs are pulled + [Parameter(Mandatory = $true)] + [String]$Name, + + # Directory into which logs are dumped and unzipped + [Parameter(Mandatory = $true)] + [String]$OutputDir, + + # Switch to turn on http logging if not already on + [Parameter(Mandatory = $false)] + [Switch]$EnableHttpLogging +) + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please make sure to install them from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + +<# +.SYNOPSIS + Gets the log files from the website +.DESCRIPTION + This function builds a file name for the log file to download, drops it into the specified $Output directory, + extracts the files from the .Zip, returns the name of the current IIS log file. +.INPUTS + $Output - the directory to which logs should be downloaded +.OUTPUTS + The log files appear in that directory +#> +function Get-LogFiles +{ + param( + [Parameter(Mandatory = $true)] + [String] + $TargetDir) + + # Create a full path for the output log file. + $fileName = "logfile $(get-date -Format yyyy-MM-dd-HHmm).zip" + if ($TargetDir.EndsWith('\') -eq $true) + { + $fileName = $TargetDir + $fileName + } else + { + $fileName = $TargetDir + '\' + $fileName + } + + # Download the log file + Write-Verbose "Downloading log file to '$fileName' ..." + Save-AzureWebsiteLog -Name $Name -Output $fileName + Write-Verbose "File successfully downloaded." + + # Unzip the contents + Write-Verbose "Extracting file contents..." + (new-object -com shell.application).namespace($TargetDir).CopyHere((new-object -com shell.application).namespace($fileName).Items(),16) + Write-Verbose "File contents successfully extracted." +} + +# Ensure the web site exists and that HttpLogging has been enabled. +$webSite = Get-AzureWebsite $Name -ErrorAction SilentlyContinue +if ($webSite -eq $null) +{ + throw "Website '$Name' does not exist." +} +elseif ($webSite.HttpLoggingEnabled -eq $false) +{ + if ($EnableHttpLogging.IsPresent) + { + Set-AzureWebsite -Name $Name -HttpLoggingEnabled $true + Write-Output "HttpLoggingEnabled now set on web site '$Name'. " + + "Re-run the script later to retrieve logs." + return + } + else + { + throw "Http Logging is not enabled on website $Name, use -EnableHttpLogging." + } +} + +# Ensure the output directory exists +if ((Test-Path $OutputDir) -eq $false) +{ + throw "The directory '$OutputDir' does not exist." +} + +# Download all of the logs, unzip and place in the $Output location +Get-LogFiles($OutputDir) + +# Define a path to the desired logs directory +$logFileActualPath = "$OutputDir\Logfiles\http\RawLogs" + +Write-Verbose "logFileActualPath is $logFileActualPath" + +# Fixes the metadata at the head of a log file +$filenames = Get-ChildItem -Path $logFileActualPath -Filter '*.log' -name +$filenames | ForEach-Object { + $updateFilePath = "$logFileActualPath\$_" + Write-Verbose "Updating header in file '$updateFilePath'." + (Get-Content $updateFilePath) | + ForEach-Object {$_ -replace "\# date", "#Fields: date"} | Set-Content $updateFilePath +} + +# Installation directory for LogParser. +$LogParserLocation = "C:\Program Files (x86)\Log Parser 2.2\LogParser.exe" + +# Parse the log file looking for any entries with HTTP status code 400 and higher. +if ((Test-Path $LogParserLocation) -eq $true) +{ + $queryLine = "`"SELECT " + $queryLine += " TO_TIMESTAMP(date,time) AS DateTime, " + $queryLine += " CASE sc-status WHEN 500 " + $queryLine += " THEN `'emerg`' " + $queryLine += " ELSE `'err`' END AS MySeverity, " + $queryLine += " s-computername AS MyHostname, " + $queryLine += " cs-uri-stem " + $queryLine += "FROM $logFileActualPath`\*.log " + $queryLine += "WHERE sc-status >= 400`"" + + & $LogParserLocation -i:IISW3C -e:5 $queryLine +} +else +{ + Write-Verbose "Unable to process log files in directory '$logFileActualPath' because LogParser is not installed." +} \ No newline at end of file diff --git a/solutions/web/New-AzureWebsitewithDB.ps1 b/solutions/web/New-AzureWebsitewithDB.ps1 new file mode 100644 index 0000000..2d6c554 --- /dev/null +++ b/solutions/web/New-AzureWebsitewithDB.ps1 @@ -0,0 +1,151 @@ +<# +.SYNOPSIS + Creates a Windows Azure Website and links to a SQL Azure DB and a storage account. +.DESCRIPTION + Creates a new website and a new SQL Azure database. If the storage account + specified doesn't exist, it will create a new storage account. + + When the SQL Azure database server is created, a firewall rule is added for the + ClientIPAddress and also for Azure services (to connect to from the WebSite). + + The user is prompted for administrator credentials to be used when creating + the login for the new SQL Azure database. +.EXAMPLE + .\New-AzureWebsitewithDB.ps1 -WebSiteName "myWebSiteName" -Location "West US" ` + -StorageAccountName "myStorageAccountName" -ClientIPAddress "123.123.123.123" +#> +param( + [CmdletBinding( SupportsShouldProcess=$true)] + + # The webSite Name you want to create + [Parameter(Mandatory = $true)] + [string]$WebSiteName, + + # The Azure Data center Location + [Parameter(Mandatory = $true)] + [string]$Location, + + # The Storage account that will be linked to the website + [Parameter(Mandatory = $true)] + [String]$StorageAccountName, + + # Users machine IP. Used to configure firewall rule for new SQL DB. + [Parameter(Mandatory = $true)] + [ValidatePattern("\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b")] + [String]$ClientIPAddress) + +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module -ListAvailable Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please install from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + +<# +.SYNOPSIS + creates a sql db and set server firewall rule based on the parameters location, + name, user id, password +.DESCRIPTION + This function creates a database server, sets up server firewall rules and then + creates a Database. It uses New-AzureSqlDatabaseServer cmdlet to create the server, + New-AzureSqlDatabaseServerFirewallRule to create the firewall rule, + New-AzureSqlDatabase cmdlet to create the database. + + ` +.EXAMPLE + $db = CreateDatabase -Location "West US" -AppDatabaseName "AppDatabaseName" + -UserName "UserName" -Password "Password" -RuleName "RuleName" + -FirewallRuleName "FirewallRuleName" -StartIPAddress "0.0.0.0" -EndIPAddress "0.0.0.0" +#> + +function CreateDatabase($Location,$AppDatabaseName, $Credential, $ClientIP) +{ + # Create Database Server + Write-Verbose "Creating SQL Azure Database Server." + $databaseServer = New-AzureSqlDatabaseServer -AdministratorLogin $Credential.UserName ` + -AdministratorLoginPassword $Credential.GetNetworkCredential().Password -Location $Location + Write-Verbose ("SQL Azure Database Server '" + $databaseServer.ServerName + "' created.") + + # Apply Firewall Rules + $clientFirewallRuleName = "ClientIPAddress_" + [DateTime]::UtcNow + Write-Verbose "Creating client firewall rule '$clientFirewallRuleName'." + New-AzureSqlDatabaseServerFirewallRule -ServerName $databaseServer.ServerName ` + -RuleName $clientFirewallRuleName -StartIpAddress $ClientIP -EndIpAddress $ClientIP | Out-Null + + $azureFirewallRuleName = "AzureServices" + Write-Verbose "Creating Azure Services firewall rule '$azureFirewallRuleName'." + New-AzureSqlDatabaseServerFirewallRule -ServerName $databaseServer.ServerName ` + -RuleName $azureFirewallRuleName -StartIpAddress "0.0.0.0" -EndIpAddress "0.0.0.0" + + # Create Database + $serverName = $databaseServer.ServerName + $context = New-AzureSqlDatabaseServerContext -ServerName $serverName -Credential $Credential + Write-Verbose "Creating database '$AppDatabaseName' in database server $serverName." + New-AzureSqlDatabase -DatabaseName $AppDatabaseName -Context $context + + return $serverName; +} + +# Create the website +$website = Get-AzureWebsite | Where-Object {$_.Name -eq $WebSiteName } +if ($website -eq $null) +{ + Write-Verbose "Creating website '$WebSiteName'." + $website = New-AzureWebsite -Name $WebSiteName -Location $Location +} +else +{ + throw "Website already exists. Please try a different website name." +} + +# Create storage account if it does not already exist. +$storageAccount = Get-AzureStorageAccount | Where-Object { $_.StorageAccountName -eq $StorageAccountName } +if($storageAccount -eq $null) +{ + Write-Verbose "Creating storage account '$StorageAccountName'." + $storage = New-AzureStorageAccount -StorageAccountName $StorageAccountName -Location $Location +} + +# Construct a storage account app settings hashtable. +$storageAccountKey = Get-AzureStorageKey -StorageAccountName $StorageAccountName +$storageSettings = @{"STORAGE_ACCOUNT_NAME" = $StorageAccountName; + "STORAGE_ACCESS_KEY" = $storageAccountKey.Primary } + +# Get credentials from user to setup administrator access to new SQL Azure Server +Write-Verbose "Prompt user for administrator credentials to use when provisioning the SQL Azure Server" +$credential = Get-Credential +Write-Verbose "Administrator credentials captured. Use these credentials when logging into the SQL Azure Server." + +# Create the SQL DB +$AppDatabaseName = $WebSiteName + "_db" +Write-Verbose "Creating database '$AppDatabaseName'." +$dbName = CreateDatabase -Location $Location -AppDatabaseName $AppDatabaseName ` + -Credential $credential -ClientIP $ClientIPAddress + +# Create a connection string for the database. +$appDBConnStr = "Server=tcp:{0}.database.windows.net,1433;Database={1};" +$appDBConnStr += "User ID={2}@{0};Password={3};Trusted_Connection=False;Encrypt=True;Connection Timeout=30;" +$appDBConnStr = $appDBConnStr -f ` + $dbName, $AppDatabaseName, ` + $Credential.GetNetworkCredential().Password, ` + $Credential.GetNetworkCredential().Password + +# Instantiate a ConnStringInfo object to add connection string infomation to website. +$appDBConnStrInfo = New-Object Microsoft.WindowsAzure.Management.Utilities.Websites.Services.WebEntities.ConnStringInfo; +$appDBConnStrInfo.Name=$AppDatabaseName; +$appDBConnStrInfo.ConnectionString=$appDBConnStr; +$appDBConnStrInfo.Type="SQLAzure"; + +# Add new ConnStringInfo objecto list of connection strings for website. +$connStrSettings = (Get-AzureWebsite $WebSiteName).ConnectionStrings; +$connStrSettings.Add($appDBConnStrInfo); + +# Link the website to the storage account and SQL Azure database. +Write-Verbose "Linking storage account '$StorageAccountName' and SQL Azure Database '$AppDatabaseName' to website '$WebSiteName'." +Set-AzureWebsite -Name $WebSiteName -AppSettings $storageSettings -ConnectionStrings $connStrSettings +Write-Verbose "Complete!" diff --git a/solutions/web/Set-FacebookAppProperties.ps1 b/solutions/web/Set-FacebookAppProperties.ps1 new file mode 100644 index 0000000..7aa956c --- /dev/null +++ b/solutions/web/Set-FacebookAppProperties.ps1 @@ -0,0 +1,45 @@ +<# +.Synopsis + Given an Azure web site that implements a Facebook application, set the AppId and AppSecret. +.DESCRIPTION + Demostrates how the settings of a web site can be set remotely using powershell. Assumes a Facebook + application that has been deployed, and changes its settings for AppId and AppSecret. +.EXAMPLE + .\Set-FacebookAppProperties.ps1 -Name myFbApp -AppId -AppSecret +#> +Param +( + + # Name of the web site the Facebook application is deployed to + [Parameter(Mandatory = $true)] + [String] + $Name, + + # Facebook app Id + [Parameter(Mandatory = $true)] + [String] + $AppId, + + # Facebook app secret + [Parameter(Mandatory = $true)] + [String] + $AppSecret +) +# The script has been tested on Powershell 3.0 +Set-StrictMode -Version 3 + +# Following modifies the Write-Verbose behavior to turn the messages on globally for this session +$VerbosePreference = "Continue" + +# Check if Windows Azure Powershell is avaiable +if ((Get-Module Azure) -eq $null) +{ + throw "Windows Azure Powershell not found! Please make sure to install them from http://www.windowsazure.com/en-us/downloads/#cmd-line-tools" +} + +$settings = @{ + "FacebookAppId" = $AppId; + "FacebookAppSecret" = $AppSecret + } + +Get-AzureWebsite -Name $Name | Set-AzureWebsite -AppSettings $settings diff --git a/solutions/web/_Add-AzureVMToVnet.md b/solutions/web/_Add-AzureVMToVnet.md new file mode 100644 index 0000000..5250b29 --- /dev/null +++ b/solutions/web/_Add-AzureVMToVnet.md @@ -0,0 +1,16 @@ +# Add-AzureVMToVNet # +## Description ## +Creates four Windows Server 2012 Virtual Machines across two separate cloud services and adds them to the same virtual network. + +If the virtual network indicated does not exist then it is created. The user is prompted for administrator credentials which can be used to logon to the virtual machines. + +This script will produce two cloud services, -1 and -2. Each cloud service will have two Virtual Machines, Host1 and Host2. + +## Scenario ## +You need multiple Virtual Machines spread across separate cloud services in the same Virtual Network. + +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## diff --git a/solutions/web/_Get-AzureWebsiteLogAnalysis.md b/solutions/web/_Get-AzureWebsiteLogAnalysis.md new file mode 100644 index 0000000..977b27a --- /dev/null +++ b/solutions/web/_Get-AzureWebsiteLogAnalysis.md @@ -0,0 +1,22 @@ +# Get-AzureWebsiteLogAnalysis # +## Description ## +Downloads IIS logs from an Azure Website and searches the log for any HTTP 400 and above status codes. + +If Http logging is not enabled on the website, then it will enable logging if the EnableHttpLogging switch is specified. + +The downloaded logs are unzipped and then fed into LogParser (if installed), querying for any HTTP status codes 400 and above. The output of the LogParser query is output to the console. + + +**Note:** This script requires an Azure Storage Account to run. The storage account can be specified by setting the subscription configuration. For example, + + Set-AzureSubscription -SubscriptionName "MySubscription" -CurrentStorageAccount "MyStorageAccount" + +## Scenario ## +You want to quickly check the IIS logs for an Azure Website to find HTTP errors. + +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## +- Set-AzureSubscription diff --git a/solutions/web/_New-AzureWebsitewithDB.md b/solutions/web/_New-AzureWebsitewithDB.md new file mode 100644 index 0000000..b27901f --- /dev/null +++ b/solutions/web/_New-AzureWebsitewithDB.md @@ -0,0 +1,23 @@ +# New-AzureWebsitewithDB # +## Description ## +Creates a Windows Azure Website and links to a SQL Azure DB and a storage account. + +If the storage account specified does not exist, the storage account will be created. + +When the SQL Azure database server is created, a firewall rule is added for the client's IP Address and also for Azure Services (to connect to from the new WebSite). + +The user is prompted for administrator credentials to be used when creating the login for the new SQL Azure database + +**Note:** This script requires an Azure Storage Account to run. The storage account can be specified by setting the subscription configuration. For example, + + Set-AzureSubscription -SubscriptionName "MySubscription" -CurrentStorageAccount "MyStorageAccount" + +## Scenario ## +You want to quickly create a new Azure Website and link it to an Azure storage account and a new SQL Azure database. + +## Requirements ## +- PowerShell Version 3.0 +- Windows Azure PowerShell June 2013 + +## See Also ## +- Set-AzureSubscription diff --git a/solutions/web/place-holder.txt b/solutions/web/place-holder.txt deleted file mode 100644 index e69de29..0000000