【问题标题】:Terminate Azure VM after 30 days automatically30 天后自动终止 Azure VM
【发布时间】:2015-12-06 13:37:12
【问题描述】:

在我今天的活动中,我在 azure 中创建了测试虚拟机,然后将其删除。由于某种原因,这次我计划创建 100 个测试 vm,并且我想实现一个调度机制(通过 powershell 或 AzureRunbook),以便创建的服务器可以在 30 天后自动删除...

问题是我可以使用 Powershell 找到云服务的创建日期,但无法找到 VM 的创建日期。很少有云服务包含我不想删除的旧虚拟机。

我正在考虑 vm 的不同命名约定,以便我可以将其用于删除时间使用-

if($vm.name -like "mypattern*")
{
     $out1 = $vm.Name
     $out2 = $vm.ServiceName
     Remove-AzureVM -Name $out1 -ServiceName $out2 -DeleteVHD
     sleep -Seconds 60
 } 

我相信除此之外一定还有更多的方法。有什么可以替代的选择。我更喜欢powershell。

【问题讨论】:

  • 如果您仍在运行 v1 虚拟机,您可以像这样获取它们:Get-AzureService |选择 DateCreated 。一旦你有了日期,你就可以从那里继续......只是一个额外的循环
  • 我的新虚拟机很少会在两三个月大的云服务中创建。我不会为每个虚拟机创建一个云服务。那是我的约束。云服务将包含新旧虚拟机。
  • 您是否为所有虚拟机启用了远程 PowerShell?
  • 我确实为所有虚拟机启用了远程 PowerShell

标签: azure azure-virtual-machine azure-powershell


【解决方案1】:

据我了解,根据您的情况,您正在尝试查找虚拟机的创建日期。有问题的虚拟机是“经典”虚拟机,这意味着它们部署到云服务容器中,而不是通过 Azure 资源管理器创建的。一些 VM 已经创建,一些将由您的脚本创建。一些云服务容器也已经存在了一段时间,有些可能更新。

我无法找到通过服务管理 API 检索 VM 创建日期的方法;但是,如果我们能够到达实际的虚拟机,那么我们还有更多工作要做。下面的脚本假定虚拟机创建日期与虚拟机上的操作系统安装日期相同(我认为这应该是一个很好的指标,我验证它不是源图像的日期,而是虚拟机创建)。为此,您需要在虚拟机上启用 PowerShell 远程端点,在创建虚拟机时默认启用该端点,并且您必须在本地管理员权限下运行该脚本,因为它会与证书存储区混淆。

$remoteCreds = Get-Credential
$maxVMAgeInDays = 30
#Classic VMs
Get-AzureVM | ForEach-Object { 
    #Need to ensure we have the self-signed VM certificate installed to authenticate and secure the connection.
    $winRmCertThumbprint = $_.Vm.DefaultWinRmCertificateThumbprint 
    $certPath = "Cert:\LocalMachine\Root\$winRmCertThumbprint"
    if (!(Test-Path -Path $certPath)){
        #Cert for VM isn't found, importing.
        $winRmCert = Get-AzureCertificate -ServiceName $_.ServiceName -Thumbprint $winRmCertThumbprint -ThumbprintAlgorithm sha1

        $certTempFile = [IO.Path]::GetTempFileName()
        $winRmCert.Data | Out-File $certTempFile

        # Target The Cert That Needs To Be Imported
        $CertToImport = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $certTempFile

        $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root", "LocalMachine"
        $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
        $store.Add($CertToImport)
        $store.Close()

        "Imported cert: $certPath"

        #clean up temp file
        Remove-Item $certTempFile
    } 

    #Retrieve the powerShell Remote port for this machine.
    $remoteUri = Get-AzureWinRMUri -ServiceName $_.ServiceName -Name $_.Name

    $osInstallDate = Invoke-Command -ConnectionUri $remoteUri -Credential $remoteCreds -ScriptBlock { ([WMI]'').ConvertToDateTime((Get-WmiObject Win32_OperatingSystem).InstallDate)  }

    $vmAgeInDays = (New-TimeSpan -Start $osInstallDate  -End (Get-Date)).Days
    if ($vmAgeInDays -gt $maxVMAgeInDays) {
        "$($_.Name) VM in $($_.ServiceName) cloud service is older than $maxVMAgeInDays ... you can remove it."
        #Add your code to remove the VM
    } else {
        "$($_.Name) VM in $($_.ServiceName) cloud service is only $($vmAgeInDays) old."        
        #Do soemthing else or just remove the else.
    }
}

脚本假定您已经执行了 Add-AzureAccount 并选择了要使用的订阅。它将提示您输入 VM 的凭据,此特定脚本假定您拥有一个已设置为适用于每个 VM 的凭据。这可以是您在创建 VM 时提供的凭据,也可以是您之后添加到每个 VM 的正确权限的凭据。既然您说您通过脚本创建了 100 台虚拟机,我的猜测是它们都将拥有相同的管理员凭据。对于您现有的虚拟机,您可能必须手动向它们添加帐户(这可能会很痛苦,具体取决于您拥有的虚拟机数量)。

脚本循环遍历每个 VM 并检查是否在本地计算机上加载了 WinRM 证书。如果没有,它会将其拉下并安装。这是保护远程 PowerShell 会话所必需的。我从Michael Washam's script on TechNet 获取了代码。

在我们知道我们拥有保护连接的证书后,他们执行远程 PowerShell 命令来检索操作系统安装日期(我在 ScioSoft blog 上找到的提示)。最后,它会根据该日期检查 VM 的年龄,然后可以执行您希望它执行的任何操作。在您的情况下,您可以将其删除。如果你真的想清理这些东西,你需要确保在删除 VM 时还清理底层磁盘等。

最后,为了改进我为您删除的任何 VM 建议的脚本,您可以然后通过指纹删除证书来清理您的证书存储。

这适用于经典虚拟机,听起来就像您拥有的那样。有人已经为您提供了一种通过标记处理基于 ARM 的虚拟机的方法,这样就无需实际处理远程命令。

【讨论】:

  • 我在执行远程 PowerShell 命令时遇到错误 - 连接到远程服务器 xxx.cloudapp.net 失败并出现以下错误。 WinRM 无法完成操作...我启用了 PS 远程处理并将执行策略设置为远程签名,即使它没有连接。
  • 其余的错误是什么?它是否将证书添加到您的证书存储中?这发生在所有机器上还是只发生在一台机器上?即使在脚本之外,您也可以使用 New-PsSession 进行连接吗?
  • 首先我尝试为单个虚拟机测试您的脚本(删除了 foreach 循环)。我能够在我的证书存储中导入证书。之后我遇到了上述错误。我相信这是 WinRM 服务的一些问题。因此,我登录到我的测试服务器并明确启用 PS-Remoting 并将执行策略设置为不受限制。即使那样我也遇到了同样的错误。但是,如果我在脚本之外的同一测试服务器上启动 PS 会话,它工作正常。
  • 这个错误除了不能完成操作还有什么?那是完整的错误信息吗?我不确定为什么会被阻止,但我能够在两台服务器上运行它而没有问题。我认为这种方法可以解决这种情况,它只是找出此时阻塞连接的原因。尝试在脚本之外针对同一测试服务器运行调用命令,而不是脚本之外的 PS-Session。
  • 老兄,它奏效了。非常感谢。你应该得到 50 赏金。 :)
【解决方案2】:

您可以通过添加标签来找到您正在搜索的虚拟机。

在 Azure Powershell 中,您可以添加资源管理器 Cmdlet Install-Module AzureRM Install-AzureRM

https://msdn.microsoft.com/en-us/library/azure/mt125356.aspx

这是来自 Microsoft 的关于标记 VM 的完整文章(Powershell 在底部)

https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-tagging-arm/

然后,当您创建这 100 个测试虚拟机时。请务必在那时标记它们,因为在创建时您会知道哪个是哪个。 使用 Set-AzureResource

$tags =@{Name="LaunchDate";Value="09-01-2015"}

Set-AzureResource -Name MyWindowsVM -ResourceGroupName MyResourceGroup -ResourceType "Microsoft.Compute/VirtualMachines" -ApiVersion 2015-05-01-preview -Tag $tags

【讨论】:

  • 我相信您提供的信息在逻辑上是非常正确的。但是因为我使用 ASM 创建了我的 VM,所以没有必要切换到 ARM(在这种情况下)。但是对于进一步的测试过程,我肯定会选择 ARM。
【解决方案3】:

这里https://social.msdn.microsoft.com/forums/azure/en-US/3da7750a-1a7d-4c62-b58a-a4b427b2520d/get-azure-vm-creationprovision-date 之前有人问过类似的问题。

简而言之,使用 PowerShell,您可以检查附加到 VM 的 VHD 的名称(仅当您从映像创建 VM 时才如此)。根据 VHD 名称,您可以确定相关 VM 的创建时间。

运行以下 cmdlet 以获取 VHD 名称:

Get-AzureVM <cloud service name> <VM name> | Get-AzureOSDisk | select medialink.

作为 PowerShell 的替代方案,您还可以使用 Microsoft Azure Management Libraries 获取云服务和虚拟机相关信息。但是,这种方法并没有带来任何额外的信息。

查看https://github.com/kimpihlstrom/azure/tree/master/Azure.Management.ListHostedServices作为使用示例以及可以获得哪些信息。

目前,除了从 VHD 的文件名中提取虚拟机的创建日期外,似乎没有其他方法可以获取虚拟机的创建日期,这仅在某些情况下才有可能。

【讨论】:

  • 我已经访问过该链接。我的虚拟机很少被迁移。他们不遵循帖子中讨论的 vhd 命名约定。在我的情况下,日期不会显示为 vhd 名称的子字符串。
【解决方案4】:

您可能想查看 Azure DevTest Labs。我没有找到太多关于它的文档,但是在提供的链接中吹捧的功能之一是能够设置自动关闭以最大限度地降低成本

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多