Posts tagged PowerShell
How To Clean up old Windows Azure diagnostics
Last week I blogged about how to easily enable Windows Azure diagnostics remotely using PowerShell. Because of this, and the simple fact you enabled diagnostics in the first place means that you now have a small collection of folders building up in the wad-* folders. Every time you deploy, you will see a new folder created for that deployment. In this post I’m going to show you how you can write a script to remove the old deployments.
What the script will do
The script will:
- Find out the current deployment id.
- Connect to blob storage
- List all of the blobs that don’t have the deployment id in the uri.
- Delete those blobs.
Note: This assumes you have 1 storage account for each deployment. If you use the same storage account for diagnostics from multiple apps you need to change the script. Also Why?
Setup
This is the same as the previous post, so if you already have done this, you can skip to the next section.
First you need to make sure you have a management certificate created and installed.
Once you have that, you need to download the PowerShell cmdlets from codeplex.
Next figure out what the thumbprint of your certificate is. You can see this in the Windows Azure management portal when you click your certificate. While you are there, make a note of your subscription Id, Storage Account Name and Key and the service name.
Defining the service and storage variables
We’ll start with the same variables used in the previous post:
# TODO: Cert thumbprint of a certificate already installed into the Windows Azure Portal $thumb = "ENTERTHUMBHERE" $cert = get-item cert:\CurrentUser\My\$thumb # TODO: Subscription Id $subid = "ENTERSUBIDHERE" # TODO: Storage Account Name $SAN = "ENTERSTORAGEACCOUNTNAMEHERE" # TODO: Storage Account Key $SAK = "ENTERSTORAGEACCOUNTKEYHERE" # TODO: Service Name $serviceName = "ENTERSERVICENAMEHERE"
Getting the current Deployment Id
Next, we’ll grab the deployment id:
$did = (Get-Deployment -ServiceName $serviceName -Certificate $cert -SubscriptionId $subid -Slot Production).DeploymentId
write-host "current deployment " + $did
Connecting to blob storage
First thing you need to do is to make sure the assemblies for storage are loaded. You can do this using
add-type -Path 'C:\Program Files\Windows Azure SDK\v1.5\ref\Microsoft.WindowsAzure.StorageClient.dll'
To access storage, we will use the CloudBlobClient class from the storage client library. This requires some credentials:
$creds = New-Object Microsoft.WindowsAzure.StorageCredentialsAccountAndKey($SAN, $SAK)
$client = New-Object Microsoft.WindowsAzure.StorageClient.CloudBlobClient("https://$SAN.blob.core.windows.net",$creds)
Grabbing a list of blobs & deleting them
One of the great things we can do is grab a list of blobs in a container using a “flat blob listing” basically, it will list everything in the container, including all the sub folders. To do this, you need to define a BlobRequestOptions object:
$bro = New-Object Microsoft.WindowsAzure.StorageClient.BlobRequestOptions $bro.UseFlatBlobListing = $true
You can grab a list of blobs for a container by using the ListBlobs method of a directory reference, which you need to grab for the container:
$wadcontainer = $client.GetBlobDirectoryReference("wad-control-container") $todelete = $wadcontainer.ListBlobs($bro) | where {$_.Uri -notmatch $did}
To delete the blob, you can simply call the Delete method.
$todelete | foreach{ $_.Delete() }
Awesome.
Full Script
Here is the full script that also handles multiple wad-* containers:
# TODO: Cert thumbprint of a certificate already installed into the Windows Azure Portal $thumb = "ENTERTHUMBHERE" $cert = get-item cert:\CurrentUser\My\$thumb # TODO: Subscription Id $subid = "ENTERSUBSCRIPTIONIDHERE" # TODO: Storage Account Name $SAN = "ENTERSTORAGEACCOUNTNAMEHERE" # TODO: Storage Account Key $SAK = "ENTERSTORAGEACCOUNTKEYHERE" # TODO: Service Name $serviceName = "ENTERSERVICENAMEHERE" # deployment Id $did = (Get-Deployment -ServiceName $serviceName -Certificate $cert -SubscriptionId $subid -Slot Production).DeploymentId write-host "current deployment " + $did $creds = New-Object Microsoft.WindowsAzure.StorageCredentialsAccountAndKey($SAN, $SAK) $client = New-Object Microsoft.WindowsAzure.StorageClient.CloudBlobClient("https://$SAN.blob.core.windows.net",$creds) $bro = New-Object Microsoft.WindowsAzure.StorageClient.BlobRequestOptions $bro.UseFlatBlobListing = $true $containersToProcess = @("wad-control-container","wad-iis-logfiles") $containersToProcess | foreach { $wadcontainer = $client.GetBlobDirectoryReference($_) $todelete = $wadcontainer.ListBlobs($bro) | where {$_.Uri -notmatch $did} $todelete | select Uri | fl | out-host $todelete | foreach { $_.Delete() } }
Tip: If you want to see what it does before committing, simply comment out the $todelete | foreach{ $_.Delete() } statement.
THIS POSTING IS PROVIDED “AS IS” WITH NO WARRANTIES, AND CONFERS NO RIGHTS, UNLESS YOU HAVE A NOTE FROM MY MUM
Enable PowerShell Remoting on Windows Azure
If it takes you more than 1 line of code, you aren’t doing it right!
I started writing this post a week ago in response to a customer request, so excited I was I even tweeted about writing a post on PowerShell. My Bad – because right after I tweeted I hit a snag – which is worthy of a whole post on its own. Ignoring the snag right now – let me tell you how to do the above.
First – a BIG shout out to the PowerShell team at Microsoft who answered my endless questions. Also a big shout out to Lee Holmes – who once again saved my bacon.
Anyway…
At long last I’ve had a chance to “play” around with the new Windows Azure features we announced at PDC 2010. I thought it would be fun to enable PowerShell Remoting in Windows Azure Roles. (Note I’m talking about Web and Worker roles here – not VM Role).
With new features such as remote desktop, startup tasks and Azure Connect – setting up PowerShell should be easy.
First, I’m going to assume you have worked through the notes/tutorials/stuff to enable Azure Connect & Remote Desktop – that way this post stays within the realms of being relatively small.
Here is our checklist:
- Make sure the OS Family in the ServiceConfiguration.cscfg is set to “2” to enable R2.
- Create a user account so you can connect to the server.
- Add a startup task to open the firewall port.
- Add the Role to Azure Connect.
- Execute Lee’s magic script to enable PowerShell Remoting
PowerShell v2 is the version you need to do remoting. Server 2008 R2 contains PowerShell v2 in the box. We can tell Windows Azure to use an R2 server by changing the OSFamily in the ServiceCOnfiguration.cscfg to 2 as shown below:
<ServiceConfiguration serviceName="AzureMemcachedTest" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="2" osVersion="*">
Next step is to create a user account so that you can actually connect to the server. The easiest way to do this is to enable remote desktop, which creates a user on the host.
Now to make sure the firewall port is open we will need. I created a .cmd file containing the following 2 commands. The first opens the firewall for WINRM, the second for ping. This was added in the root folder of my role project.
netsh advfirewall firewall add rule name="Windows Remote Management (HTTP-In)" dir=in action=allow service=any enable=yes profile=any localport=5985 protocol=tcp
netsh advfirewall firewall add rule name="ICMPv6 echo" dir=in action=allow enable=yes protocol=icmpv6:128,any
Then I added a startup task to ServiceDefinition.csdef:
<Startup>
<Task commandLine="EnablePowershellRemoting.cmd" executionContext="elevated" taskType="foreground"/>
</Startup>
Next add the Role to Azure Connect. I’ll assume you know how to do this.
Now deploy your service. Once deployed, do the final step to connect the Azure connect network, and make sure the agent is installed on your computer.
The final step is to “turn on” PowerShell Remoting. For numerous reasons, you cannot just run a startup task with “Enable-PSRemoting” as the command. The biggest reason is that startup tasks run as local system and thus cannot actually complete the Enable-PSRemoting command.
This is where I got stuck for 3 days until Lee shared his script. The script is below and is fairly easy to follow. Basically it will connect to the VM and create a scheduled task to enable-psremoting.
##############################################################################
##
## Enable-RemotePsRemoting
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Enables PowerShell Remoting on a remote computer. Requires that the machine
responds to WMI requests, and that its operating system is Windows Vista or
later.
.EXAMPLE
Enable-RemotePsRemoting <Computer>
#>
param(
## The computer on which to enable remoting
$Computername,
## The credential to use when connecting
$Credential = (Get-Credential)
)
Set-StrictMode -Version Latest
$VerbosePreference = "Continue"
$credential = Get-Credential $credential
$username = $credential.Username
$password = $credential.GetNetworkCredential().Password
$script = @"
`$log = Join-Path `$env:TEMP Enable-RemotePsRemoting.output.txt
Remove-Item -Force `$log -ErrorAction SilentlyContinue
Start-Transcript -Path `$log
## Create a task that will run with full network privileges.
## In this task, we call Enable-PsRemoting
schtasks /CREATE /TN 'Enable Remoting' /SC WEEKLY /RL HIGHEST ``
/RU $username /RP $password ``
/TR "powershell -noprofile -command Enable-PsRemoting -Force" /F |
Out-String
schtasks /RUN /TN 'Enable Remoting' | Out-String
`$securePass = ConvertTo-SecureString $password -AsPlainText -Force
`$credential =
New-Object Management.Automation.PsCredential $username,`$securepass
## Wait for the remoting changes to come into effect
for(`$count = 1; `$count -le 10; `$count++)
{
`$output = Invoke-Command localhost { 1 } -Cred `$credential ``
-ErrorAction SilentlyContinue
if(`$output -eq 1) { break; }
"Attempt `$count : Not ready yet."
Sleep 5
}
## Delete the temporary task
schtasks /DELETE /TN 'Enable Remoting' /F | Out-String
Stop-Transcript
"@
$commandBytes = [System.Text.Encoding]::Unicode.GetBytes($script)
$encoded = [Convert]::ToBase64String($commandBytes)
Write-Verbose "Configuring $computername"
$command = "powershell -NoProfile -EncodedCommand $encoded"
$null = Invoke-WmiMethod -Computer $computername -Credential $credential `
Win32_Process Create -Args $command
Write-Verbose "Testing connection"
Invoke-Command $computername {
Get-WmiObject Win32_ComputerSystem } -Credential $credential
Piece of cake really.
Once you have the script saved, you can execute it like
PS> $computername = "WhateverTheComputerNameOfTheInstanceIs"PS> .\Enable-RemotePSRemoting.ps1 $computername
Once it finishes executing, you should be able to connect using:
PS> Enter-PSSession –ComputerName $computername –Credential RemoteDesktopUsername
Then you can work interactively – try get-process as an example.
Pretty neat, and great for debugging!
THIS POSTING IS PROVIDED “AS IS” WITH NO WARRANTIES, AND CONFERS NO RIGHTS